Archives mensuelles : décembre 2014

Attraper une exception en Powershell

Avec Powershell il est possible d’attraper des exceptions. Une Exception est un signal qu’une commande envoie lorsque une erreur se produit.

Ce qui est intéressant avec cette approche est que nous pouvons regrouper une série de commandes dans un script block, et attraper toutes les erreurs d’une seule et même façon.

Sans ça nous devrions vérifier chaque commande et agir en conséquence ce qui augmenterait considérablement la quantité de code à écrire.

On utilise les exceptions avec le trio: Try, Catch, Finally

  1. Try (Essayer), permet d’essayer toutes les commandes dans un script block.
  2. Catch, récupère toutes les erreurs produites par les commandes dans le script block
  3. Finally, permet d’exécuter un script block après que le catch ait fini de traiter les exceptions reçues. (non traité dans cet article)

Voici un exemple:

Dans cet exemple nous listons les fichiers dans le répertoire actuel, nous testons si « localhost » répond au ping, et nous créons le répertoire « c:\temp ».

Toutes ces commandes peuvent avoir des erreurs indépendantes, et pour les attraper, nous allons continuer le code avec la partie catch.

Maintenant nous pour toute exception attrapée nous pouvons afficher le message.

Imaginons maintenant que nous voudrions être plus fins.

Par exemple, la commande New-Item peut produire une exception si le répertoire C:\TEMP existe déjà. Et nous voudrions customiser le message que dans ce cas là.

Tout d’abord il faut trouver la bonne exception, et ce n’est pas simple, mais voici un truc.

On indique tout d’abord à Powershell de s’arrêter si une erreur se produit (normalement il continue) avec la commande suivante:

Ensuite on reproduit l’erreur, dans notre cas on crée le répertoire deux fois pour que la deuxième fois une exception se produise.

Une fois l’exception reçue, on peut regarder son nom exact avec ceci:

Notre exception particulière qui apparaît lorsque on essaye de créer un dossier qui existe déjà est : System.IO.IOException.

Du coup on peut faire un catch dédié à ce type d’exceptions avec ceci:

Notre exception IO sera attrapée par son catch individuel et pourra être traitée à sa façon.

 

SID

Voici comment récupérer le SID d’un utilisateur très rapidement.

Si on regarde cette commande d’un peu plus près:

On crée un objet NT account a partir d’un nom d’utilisateur:

Et ensuite on utilise la méthode Translate qui permet de récupérer un objet Security Indentifier

On peut également trouver le nom d’un Security Principal à partir d’un SID.

Pour ceci on commence par:

Le résultat sera:

 

 

Partager ce contenu

sIDHistory

Pour les besoins d’un projet, j’ai besoin de récupérer la liste des SIDs dans le champs sIDHistory de tous les utilisateur Active Directory.

Ceci sans utiliser les dernières cmdlets Active Directory disponibles depuis Windows 2008.

Alors comme on dit, on va faire de l’ADSI old school.

Un SID en très court:

Un Security Identifier (SID) est un chiffre complexe qui permet à un Security Principal (utilisateur, ordinateur, groupe) d’être identifié. Cet identifiant est placé dans les Access Control List (ACL) et reçoit des droits d’accès.

Par exemple on peut donner un droit de lecture d’un fichier à un utilisateur. Windows pour ça va créer un Access Control Entry (ACE), contenant le SID de l’utilisateur ainsi que le droit, Read, et va placer cet ACE dans l’ACL du fichier. Powershell a d’ailleurs d’excellentes cmdlets pour traiter tout ça: Get-Acl et Set-Acl.

Lors des migrations d’utilisateurs entre domaines ou entre forêts Active Directory, il est nécessaire de se rappeler l’identifiant utilisé dans la forêt d’origine, ceci car en migrant, l’utilisateur recevra un nouvel identifiant, mais tous les fichiers sur les serveurs sont protégés en utilisant l’ancien SID.

Du coup lorsqu’on migre des utilisateurs d’un domaine vers un autre, souvent on garde l’ancien SID dans le champs sIDHistory.

J’ai créé une cmdlet, Get-sIDHistory, qui permet de récupérer les SIDs dans la sIDHistory et sauvegarde le résultat dans un fichier CSV.

voici le Get-Help de la cmdlet:

Seuls le Domaine et le Path sont des paramètres obligatoires, le premier pour indiquer le domaine à scanner, et le deuxième pour définir le nom du fichier CSV à générer.

Le Serveur est optionnel et permet de cibler un DC en particulier.

Append est utilisé pour ne pas écraser le fichier CSV si on exécute cette cmdlet en boucle sur plusieurs domaines.

Et voici le code:

Partager ce contenu

Measure-Time

Une question StackOverflow était la suivante: Comment peut-on faire pour avoir l’équivalent de la commande time de Linux/Unix sur Windows à travers Powershell.

Cette commande permet de savoir le temps que passe une expression ou une autre commande en mode User et mode System. Dans le monde Windows le mode System est le mode Kernel, pendant lequel, si une erreur se produit, la machine fait un crash dump (le fameux blue screen of death).

La première réaction est bien sûr d’utiliser la cmdlet Measure-Command, qui permet mésurer le temps qu’une commande utilise pour s’exécuter.

Or Measure-Time ne mesure pas plus en détail le temps Kernel versus le temps User: ça ne donne que l’elapsed time.

Du coup nous allons créer notre propre cmdlet pour simuler cette commande time.

On appellera cette cmdlet Measure-Time.

La cmdlet utilise du C# pour importer la fonction GetProcessTimes depuis Kernel32.DLL. Elle va également démarrer un process avec la commande passée en paramètre, et une fois le process terminé elle pourra à travers GetProcessTimes mesurer les temps passés en mode Kernel, User et l’elapsed time.

J’ai ajouté un switch appelé -Silent qui permet de cacher le output généré par la commande.

Partager ce contenu