Archives mensuelles : septembre 2014

Charger un fichier CSV dans Excel

Avec Powershell, nous avons pris l’habitude de travailler avec des fichiers CSV. Il est facile de créer un array d’objets de type PSCustomObject et envoyer le tout dans un fichier CSV à travers la cmdlet Export-CSV.

Il est parfois nécessaire de charger un fichier CSV dans Excel pour faire des traitements particuliers tels que la création de graphiques et autres tableaux croisés dynamiques si chers à certains.

Cet article montre comment, à partir de Powershell on peut charger un fichier CSV directement dans Excel.

Créons un fichier CSV

Attention de bien utiliser l’extension de fichier « .TXT » car Excel traite les fichiers avec l’extension CSV différemment.

Démarrons Excel:

Chargeons le fichier CSV dans Excel:

Voyons ces paramètres, on commence par le nom du fichier, ensuite on indique que le fichier a été créé sous Windows, ceci est important, car des fichiers Macintosh ou MSDOS auraient un format différent.

Ensuite on indique à partir de quelle ligne on traite les données.

On définit que le fichier est bien délimité.

Que les données Texte sont entre des guillemets.

Que si on trouve plusieurs guillemets on ne les regroupe pas.

Que Tab n’est pas un caractère de délimitation

Que le point-virgule n’est pas un caractère de délimitation, attention en France il faut mettre $true car c’est le délimiteur par défaut.

Que la virgule (le comma in english), est le caractère qu’on cherche.

Et voilà

CSV

Trouver son mot de passe Excel

Vous avez protégé une spreadsheet Excel avec un mot de passe, et pas moyen de le retrouver. Ce script permet d’utiliser la technique appelée Brute Force pour le récupérer.

En fonction de la taille du mot de passe, il se pourrait que ça prenne très longtemps, voire trop longtemps, donc ceci est valable pour les mots de passe courts.

RAPPEL: Ne pas utiliser sur des fichiers Excel qui ne vous appartiennent pas. Ce serait contre je ne sais quelle loi.

Le but de ce script est de voir l’utilisation de jobs Powershell de façon récursive. J’ai expliqué les jobs ici et les fonctions récursives ici.

Pour cet exercice, nous allons combiner les fonctions récursives et les jobs. Nous allons faire des jobs récursifs!

Chaud devant.

Nous commençons notre script par définir un paramètre $maxPasswordLength, on va lui donner une valeur par défaut de 4.

On récupère l’endroit où se trouve le script qui va devenir notre répertoire par défaut.

On va utiliser les formes Windows pour un Open Files dialog box, ceci est une petite fenêtre qui permet de choisir le fichier Excel à traiter.

Le fichier Excel à traiter peut être récupéré à travers la variable membre FileName de l’objet Dialog Box.

On connait le nom du fichier, démarrons Excel.

Nous n’avons pas besoin qu’il soit visible.

Maintenant ouvrons notre fichier.

Et sélectionnons la spreadsheet active, celle par défaut.

Construisons une chaîne de caractères avec la liste des caractères que nous voulons essayer pour trouver le mot de passe.

Avec cette liste de caractères, nous allons créer toutes les combinaisons possibles. Nous allons stocker ces résultats dans un array.

Nous créons une boucle qui pour chaque niveau de la chaîne de caractères, va créer un job qui s’exécutera dans le background afin de paralléliser au maximum la génération des résultats.

A noter la création des arguments qui contiennent un script block appelé $buildList. Ce script block définit la fonction BuildList, qui étant récursive, doit pouvoir s’appeler. La définition de la fonction doit être faite dans le script block passé comme argument, sinon elle ne serait pas visible par le job. Les jobs s’exécutant dans leurs propre console, n’ont pas accès au variables définies dans notre script principal. Du coup on crée un script block, on y met tout ce que le job doit voir, et on lui passe comme paramètre. Comme le type [scriptblock] et les paramètres ne font pas bon ménage, on triche et on lui passe comme une [string], on devra le caster vers un [stringblock] à la réception.

Voici le script block:

Dans ce script block, nous commençons par recréer notre script block (il est passé comme une string).

Nous rentrons dans une boucle, qui pour chaque caractère de notre chaîne, va générer une string à sauvegarder.

Ensuite nous allons regarder le niveau dans la chaîne, si on est au max, nous avons tous les éléments pour créer la chaîne de résultats à retourner au niveau inférieur. A noter la ligne

Ceci envoie une string sur la console. La cmdlet Receive-Job, reçoit  tout ce qui a été envoyé sur la console, ainsi nous pouvons capturer tous les résultats. Par contre s’il y a une erreur quelque part, elle arriverait sur la console du job, et l’appelant la recevrait aussi, ce qui pourrait fausser ce qui est attendu. Donc bien débugger un job avant de se lancer.

Si nous n’avons pas exploré toutes les combinaisons, nous allons créer d’autres jobs, de façon récursive.  Et nous allons attendre avec Wait-Job, que les niveaux successifs aient fini. On récupère leurs résultats, et on les passe à l’appelant.

C’est compliqué car les fonctions récursives le sont, et en combinant ceci avec des jobs, ça devient franchement difficile à discerner complètement ce qui se passe au premier abord.

Une fois tous les résultats reçus à travers Receive-Job nous avons toutes les chaînes à essayer pour cracker notre spreadsheet.

Pour chaque élément dans la liste des résultats

Nous allons essayer la string comme un mot de passe et enlever la protection de la spreadsheet. On va attraper toutes les exceptions, car on sait que tous ces essais, et potentiellement, sauf un, produira des erreurs.

Et on vérifie si la spreadsheet est débloquée.

Finalement une fois toutes les combinaisons exécutées on peut sortir de Excel

Voilà.

Voici le script complet

Toutes les combinaisons d’un array

Le problème : calculer toutes les combinaisons d’un array à 1 dimension avec N éléments.

Donc si on avait un array à 2 éléments, et que toutes nos array avaient toujours 2 éléments (ou 3, peu importe).

On pourrait imaginer une solution en dur tel que:

Bien que le résultat soit correct, ce n’est pas terrible, car au-delà du 2ème élément ça ne marcherait plus. Voici le résultat:

 

Le meilleur moyen de régler ce problème c’est à travers les fonctions récursives. Une fonction récursive est une fonction qui s’appelle elle-même tant que des conditions sont remplies.
Par exemple nous allons écrire une fonction qui va vérifier s’il y a encore des éléments à traiter dans l’array et si c’est le cas elle s’appelle pour traiter le niveau supplémentaire.

Le résultat:

first
first first
first first first
first first first first
first first first second
first first first third
first first first fourth
first first second
first first second first
first first second second
first first second third
first first second fourth
first first third
first first third first
first first third second
first first third third
first first third fourth
first first fourth
first first fourth first
first first fourth second
first first fourth third
first first fourth fourth

etc.

 

La dimension du néant

Définissons une variable $a

$null c’est le void, c’est l’inexistence de valeur. C’est très utilisé lorsqu’un objet n’est pas correctement défini et donc il ne pointe vers aucune valeur.

Maintenant que $a vaut $null, faisons quelques essais:

Est-ce que $a est plus petit que 0

Est-ce que $a est plus grand que -1

Est-ce que $a est égal à zéro

J’en perds mon ℝ. Je n’ai pas de valeur, et j’ai quelque chose qui vaut moins que 0, est plus grand que tous les nombres négatifs et ne vaut pas zéro.

Essayons de comprendre.

$a équivaut à $null, en fait c’est void, un terme en C qui en principe équivaut à vide. Mais ici on ne parle pas du vide, qui est l’absence d’éléments (le panier est vide car il ne contient aucune pomme) on parle de néant. Le néant est l’absence d’ensembles.

void en Powershell est représenté par la valeur $null. D’ailleurs on peut caster vers un void avec [void].

Ceci ne retourne rien:

Et ceci permet d’y voir un peu plus clair

Ce qui porte vraiment à confusion est le cast suivant:

Ici Powershell nous aide en se disant que bien que $null ne soit pas une valeur, si vraiment on doit en choisir une ce sera celle-là.

D’ailleurs c’est pareil avec [bool]

Par contre déclarer une variable avec $null ne crée pas l’objet. Et accéder à une fonction membre d’un objet nul est fortement tabou.

 

Donc nous avons à faire avec le néant.

Le néant représenté par $null est un concept en dehors des valeurs. En dehors des ensembles mathématiques.

Du coup, $null est plus petit que les valeurs positives, est plus grand que les valeurs négatives, et ne vaut pas zéro.

Lorsqu’on trouve une variable ou un objet, ou une méthode qui vaut $null, et bien ça a une énorme valeur.  Et on se presse de la corriger, car généralement il s’agit d’une variable non définie, mal définie, mal passée, mal castée, et ça finit par des résultats non souhaités ou un crash dump et dans le cas de Powershell, un mur de rouge qui s’affiche dans la console.

Le néant peut avoir une grande valeur.

Partager ce contenu

Création d’une interface graphique

Ecrit par @mickyballadelli

Le 4eme problème des Mini Scripting Games de Ed Wilson est le suivant:

Créer un script qui liste les processus en exécution, ensuite créer une interface graphique pour les visualiser, et permettre à l’utilisateur de sélectionner un ou plusieurs processus pour les arrêter.

Alors voici :

Avant tout, il faut qu’on dise à Powershell qu’on va utiliser deux librairies de fonctions, la première pour créer l’interface graphique (GUI) à travers les Forms de Windows, et la deuxième pour utiliser des références géométriques afin d’indiquer la taille et la position dess contrôles graphiques.

Nous allons ensuite créer notre interface avec une forme qui contiendra les objets dont nous allons avoir besoin :

Définition de la taille et du titre de la fenêtre principale :

Création du bouton pour lister les processus :

On peut lui donner un nom:

Lui définir une taille (largeur, hauteur) :

Lui dire quoi afficher :

Définir que si on appuie sur Tab, c’est ce bouton qui reçoit en premier le focus :

Lui dire où se positionner par rapport à l’origine en haut à gauche de notre forme :

Lui dire que si on click dessus, on veut être appelés dans notre script block :

Et finalement l’ajouter à notre forme :

Nous allons faire la même chose avec le bouton Kill

Nous allons maintenant créer notre ListView, ce type de contrôle nous permet de créer des listes avec plusieurs colonnes et on va le customiser un peu :

C’est notre 3eme contrôle dans notre forme, le 3eme à recevoir le focus en navigation Tab

Définition de la taille et emplacement :

Le type de view, sachant qu’il y a plusieurs types un peu comme la fenêtre Explorer, avec les petits ou grands icônes, Tile (icone + texte), et Details.

Un peu de cosmétique ce qui permettra de créer une bordure à nos éléments de la liste :

Par défaut, lors de la sélection d’un élément, ListView reflète l’élément sélectionné mais pas ses sous-éléments. Nous voulons que toute la ligne soit sélectionnée d’un point de vue visuel.

Marrant comment un bit peut grandement changer les choses, en mettant AllowColumnReorder à 1, les colonnes de notre liste peuvent être réorganisées comme on le désire :

On va permettre la création et gestion des scroll bars automatiquement :

Par défaut, une ListView fait le tri que sur la première colonne, or nous allons en avoir plusieurs, ce qui veut dire que nous allons devoir gérer le triage nous-mêmes à travers une fonction qu’on verra plus bas appelée SortList. Du coup, on indique à la ListView que nous ne voulons pas de Sorting, et que si quelqu’un clique sur une colonne, on veut être appelé avec l’ID de la colonne comme paramètre.

Maintenant gérons la structure de notre ListView, créons les colonnes et donnons une largeur à chaque colonne :

Les ListViews nous permettent de stocker un objet data perso quel qu’il soit au sein de la Liste, des colonnes et des éléments. Nous allons en profiter pour placer dans chaque colonne un objet qui se souviendra la direction du triage, Ascending ou Descending :

Dernière ligne droite, gérons les changements de taille de notre fenêtre, pour que la taille de la ListView soit toujours en fonction de celle de la forme, ceci se fait avec un callback sur un script block :

Il ne manque plus que les données, dont j’ai regroupé toute la fonctionnalité dans une fonction :

Notre IHM est prête, nous pouvons l’afficher :

Voyons maintenant notre fonction AddData

Les paramètres de notre fonction sont un array contenant la liste des processus ainsi que la ListView.

Commençons par indiquer à la ListView que nous allons la mettre à jour, ceci permettra à la ListView de bloquer l’interface pendant que la maj s’opère :

Cette fonction sera utilisée également par le bouton List ce qui rafraichira la liste, Du coup nettoyons d’eventuels élément avant d’ajouter notre nouvelle liste.

Nous allons maintenant traverser chaque élément de l’array, et placer toutes les données dans un ListViewItem. Celui-ci est composé d’un Item, et de ses sous-items, chaque sous item étant une colonne :

Par exemple, la colonne avec l’ID du processus sera ajouté ainsi :

Et ça nous permet de formater les données de chaque colonne comme on le désire, ici la taille de la mémoire utilisée sera en mégaoctets :

Une fois toutes les colonnes remplies, nous pouvons insérer l’item dans la liste :

Une fois notre liste finalisée, nous pouvons dire à la ListView qu’on a fini :

Voyons maintenant notre fonction de triage, SortList:

Dans la première partie nous cherchons à savoir sur quelle colonne l’utilisateur a cliqué pour ensuite récupérer notre objet Tag qui contient la direction du triage. Ensuite nous laissons Powershell effectuer le triage dans la bonne direction avec la cmdlet Sort-object.

Voici maintenant les callbacks des boutons.

Celui du bouton List est très simple, si on click on fait un refresh de la liste :

Celui du bouton Kill est un peu plus compliqué, nous devons trouver l’ID du process. La colonne ID est la deuxième, même si l’utilisateur bouge les colonnes de place. Donc on va directement sur cette colonne récupérer l’ID du process et trouver l’objet dans la liste des processus équivalent. Ensuite nous allons dire à cet objet d’arrêter le processus. Le tout dans un foreach pour chaque élément de la liste sélectionné.

Voici un screen shot du script:

Voici le script complet:

Partager ce contenu

Gérer le progrès d’un script

Ecrit par @mickyballadelli

Le 3eme problème des Mini Scripting Games de Ed Wilson est le suivant:

Un de vos collègues a créé un script qui met à jour des données sur les postes d’utilisateurs chaque semaine. Ce script peut prendre un certain temps pour s’exécuter, jusqu’à cinq minutes dans certains cas et ceci peut être perçu par les utilisateurs comme un problème informatique puisque leur poste ne répond plus pendant l’exécution du script.

On nous demande de modifier le script pour donner un feedback visuel pour l’avancement des tâches en cours. En fait on nous demande seulement le proof of concept de cette solution.

Notre tâche est de coder un script qui compte de 1 à 25 et montrer le progrès effectué de façon visuelle. On nous demande aussi de montrer de façon visuelle ce que fait le script, dans notre cas, le script compte.

Donc voici :

(J’ai ajouté un sleep exprès pour que la barre de progrès reste visible, sinon ça irait trop vite.)

Et voilà

Partager ce contenu

Géstion des fichiers CSV

Ed Wilson, Microsoft Scripting Guy, a annoncé le 2eme problème dans la série des Mini Scripting Games.

Ce coup-ci il s’agit d’aller lire le contenu d’un fichier CSV, qui contient 5 colonnes de données. En choisir 3 et créer un objet custom qui ne contient que des colonnes. Il faut ensuite créer un nouveau fichier CSV avec nos 3 colonnes.

Ed ne mentionne pas si on peut utiliser des cmdlets qui faciliteraient beaucoup la tâche. Du coup ma solution est en deux partie, la première n’utilise pas de cmdlets, et la deuxième les utilise.

Voici le fichier CSV de input :

Un peu de préparation pour déclarer des variables pointant vers les fichiers d’entrée et sortie :

Première solution (version longue, director uncut), pas forcément la meilleure.

Lisons le contenu du fichier CSV :

Nous avons maintenant un array $a qui contient un élément par ligne.

Nous devons maintenant créer un custom object. L’objet ne doit contenir que des colonnes d’après l’énoncé. Du coup je choisis de créer un objet qui contient des arrays que j’appelle c1, c2 et c3. Un par colonne :

J’ajoute un petit compteur qui m’aidera à savoir combien d’éléments sont dans les arrays. Je pourrais évidemment demander à une de ces arrays, mais par simplicité de lecture je préfère placer ce compteur au même niveau que les arrays.

Je vais choisir les colonnes a, c et e et créer une boucle pour stocker les données dans les arrays de notre objet. Lors de la boucle je vais également extraire les données sans les virgules.

Maintenant que nous avons les données dans le format voulu, nous allons les sauvegarder dans un autre fichier CSV comme demandé dans l’énoncé.

Création d’un fichier vide :

Sauvegarde des données en ajoutant les virgules comme délimiteur :

Voici mon fichier output :

Ca c’était la version loooongue, on peut faire beaucoup plus rapide, surtout avec les cmdlets et le ‘piping’ qui vont bien:

Et voilà

Partager ce contenu

Vérification de variables

Ed Wilson, le Microsoft Scripting Guy qui tient un excellent blog sur Powershell, vient de démarrer des Mini Scripting games.

Dans ce premier jeu Ed soumet un problème intéressant qui devrait nous arriver à tous (enfin ceux qui font du Powershell).

Imaginons que nous devons lire un fichier CSV pour récupérer les attributs Active Directory d’un utilisateur. Nous devons ensuite mettre à jour ces attributs dans l’Active Directory, or il se peut que des attributs manquent ou qu’ils contiennent des espaces ou des tab, finalement des attributs mal renseignés. Ceci résulte en une erreur lorsqu’on essaye de mettre à jour l’AD.

Ed demande comment on peut régler le problème en vérifiant que ce qui est remonté est valable.

Par valable Ed dit qu’il faut qu’on vérifie tous les cas possibles où les attributs peuvent poser problème.

Voici ma liste des cas possibles:

  • Null
  • Non-null mais vide
  • Contient 1 ou plusieurs espaces
  • Contient 1 ou plusieurs tabs

Ed dit ensuite qu’il voudrait seulement voir le test effectué pour qu’on se focalise sur le problème, de ce fait je vais ignorer la lecture du fichier CSV et la mise à jour de l’AD, je ne regarde que le test qu’on va effectuer pour tester la valeur.

Ed d’ailleurs donne un exemple :

Évidemment cet exemple ne couvre qu’un seul cas.

Et bien pour répondre à ce problème, j’utiliserais une expression régulière.

Voici les explications.

J’utilise l’opérateur de condition -match qui permet de vérifier une chaine avec une expression régulière.

Les expressions régulières permettent de faire beaucoup de choses avec quelques caractères :

  • Avec ^ j’indique le début d’une chaine de caractères.
  • Entre [ ] j’indique des cas possibles que je veux traiter, c’est-à-dire des caractères spécifiques que je veux trouver.
  • Avec \s j’indique un espace
  • Avec \t j’indique un tab
  • Avec { } j’indique que ce qui est entre les [ ] peut se répéter
  • Avec 0 je couvre le cas où la chaine est vide
  • Avec la virgule je dis que le 0 n’est pas le seul cas
  • Ne pas mentionner d’autres cas (je finis directement avec } après la virgule) veut dire que tous les autres cas sont compris
  • Avec $ j’indique la fin de la chaine

Les cas pris en compte par cette ligne de code sont:

Et voilà

Partager ce contenu

2048 en Powershell

Ecrit par @mickyballadelli

Voici une version du jeu 2048 écrit en Powershell. Le code original est écrit par Gabriele Cirulli en JavaScript. J’en ai fait une version simple en Powershell avec un GUI basé sur les formes et les labels.

Enjoy!

Le but est de combiner plusieurs cases entre elles lorsque leurs valeurs sont les mêmes et d’atteindre 2048. Le jeu peut aller jusqu’à 8192.

Utiliser les flèches pour les déplacements.

Partager ce contenu

Replication Status

Ecrit par @mickyballadelli

Le script ci-dessous vérifie la santé de la réplication Active Directory et génère un rapport en HTML.

Le script se base sur la commande repadmin et génère un output en CSV. Le fichier CSV est ensuite importé pour générer une version en HTML.

Les données de réplication de tous les DCs de la forêt sont vérifiés (d’où le temps qu’il faut pour la commande repadmin pour qu’elle s’exécute).

Dans cette version le script ne prend pas de paramètres, par contre il est facile de le customiser en fonction de ses besoins.

Point intéressant, la transformation du code erreur retourné par repadmin en un message lisible par un humain.

Replication errors as of « +[datetime]::Now+ »

Replication OK as of « +[datetime]::Now+ »

Partager ce contenu