Jacques's profilejanelPhotosBlogLists Tools Help
    August 09

    Naissance du blog MOF sur Technet

    Enfin ! L’équipe MOF de Microsoft a son blog sur Technet. Ce blog devrait permettre à la communauté IT du monde entier d’exprimer ses joies, ses peines et ses attentes directement aux concepteurs du Microsoft Operations Framework.
     
     
    Dans l’attente d’un dialogue constructif !
     
    Janel
    August 06

    Le cas du nombre de pages résolu

    Bon, dans mon billet précédent je proposais un script pour récupérer les statistiques d’une série de documents Word. Ma méthode, très artisanale, s’appuyait sur les propriétés Words, Sentences et Paragraphs d’un objet Document. Malheureusement, la classe Document n’a pas de propriété Pages, ce qui n’était pas sans affaiblir l’intérêt de mon script.
     
    Voilà l’erreur réparée : en fouillant la documentation MSDN pour essayer de comprendre comment on peut récupérer le nombre de pages d’un document, je suis tombé sur la méthode ComputeStatistics() qui correspond à ce que je cherchais. O joie, cette méthode retourne toutes les informations que je récoltais dans mon script, et comble de bonheur, elle semble beaucoup, beaucoup, beaucoup plus rapide que ma technique artisanale.
     
    Voici donc le script dans une version améliorée et fonctionnellement « complète » :
     
    # measure-document.ps1
    #
    # Fournit des statistiques sur le(s) document(s) passé(s) par le pipeline:
    #
    #   - Characters = Nombre de caractères dans le document (hors 'espace')
    #   - Lines      = Nombre de lignes dans le document
    #   - Name       = Nom du document
    #   - Pages      = Nombre de pages dans le document
    #   - Paragraphs = Nombre de paragraphes dans le document
    #   - Path       = Chemin du document
    #   - Size       = Taille du document (en octets)
    #   - Spaces     = Nombre de caractères 'espace' dans le document
    #   - Words      = Nombre de mots dans le document
    #
    # Usage:
    #
    # dir *.doc | measure-document
    #
     
    # section exécutée avant le traitement du premier document:
    begin
    {
      # ouverture de l'application:
      $wordapp = new-object -com word.application
     
      # création de la variable à utiliser pour les paramètres optionnels laissés vides:
      $m = [system.type]::missing
    }
     
    # section exécutée pour chaque document:
    process
    {
      # ouverture du document dans Word:
      $doc = $wordapp.documents.open($_.fullname,$m,$true,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m)
     
      # récupération des statistiques:
      $characters = $doc.ComputeStatistics("WdStatisticCharacters")
      $lines = $doc.ComputeStatistics("WdStatisticLines")
      $name = $doc.name
      $pages = $doc.ComputeStatistics("WdStatisticPages")
      $paragraphs = $doc.ComputeStatistics("WdStatisticParagraphs")
      $path = $doc.path
      $size = $_.length
      $spaces = $doc.ComputeStatistics("WdStatisticCharactersWithSpaces") - $characters
      $words = $doc.ComputeStatistics("WdStatisticWords")
     
      # fermeture du document:
      $doc.close()
     
      # construction de l'objet qui contiendra tous les résultats:
      $result = new-object PSObject
     
      # ajout des résultats:
      $result | add-member NoteProperty Characters $characters
      $result | add-member NoteProperty Lines $lines
      $result | add-member NoteProperty Name $name
      $result | add-member NoteProperty Pages $pages
      $result | add-member NoteProperty Paragraphs $paragraphs
      $result | add-member NoteProperty Path $path
      $result | add-member NoteProperty Size $size
      $result | add-member NoteProperty Spaces $spaces
      $result | add-member NoteProperty Words $words
     
      # affichage des résultats:
      $result
    }
     
    # section exécutée après le traitement du dernier document:
    end
    {
      # fermeture de l'application:
      $wordapp.quit()
      $wordapp = $null
    }
     
    Vous noterez que j’ai enlevé le calcul du nombre de phrases. Cette statistique n’est pas fournie par la méthode ComputeStatistics() et la technique que j’employais dans ma première version était assez lente. L’information ne me semblait pas essentielle, j’ai donc privilégié le gain de performance pour le script en la retirant purement et simplement. Si vous en avez besoin, vous devriez pouvoir l’incorporer à partir de mon premier script.
     
    J’avais dans l’idée d’implémenter un paramètre -total (ou quelque chose comme ça) qui, au lieu ou en plus de fournir les informations pour chaque document, aurait fourni le total des différents compteurs pour l’ensemble des documents traités. La tâche n’aurait pas été bien compliquée, mais elle l’était encore bien trop au regard de la possibilité qui est offerte à l’utilisateur d’obtenir les mêmes données (et davantage) avec la commandelette measure-object :
     
    PS> dir *.docx | measure-document | measure-object lines, pages -sum -average | format-table -auto
     
    Count Average Sum Maximum Minimum Property
    ----- ------- --- ------- ------- --------
        2   267,5 535                 Lines
        2     7,5  15                 Pages
     
    Et voilà. Pourquoi se torturer le cerveau quand PowerShell fournit déjà les outils qui vont bien ? De l’intérêt d’utiliser un PSObject pour profiter de la faculté de measure-object de mesurer les propriétés d’une collection d’objets.
     
    Bon. Je pense que je vais m'en tenir là avec Word pour cette série. La prochaine fois, promis, je parle d’Excel J.
     
    Janel
    August 05

    Le cap des 20 000 visites franchi aujourd'hui

    Le 31 janvier de cette année, je me réjouissais de voir franchir le cap des 10 000 visites sur mon blog. A l’époque, je calculais à la louche que cela représentait une moyenne d’environ 1000 visites par mois, mon blog ayant vraiment démarré en mai 2006.
     
    Aujourd’hui, soit à peine plus de six mois plus tard, c’est le cap des 20 000 visites qui vient d’être franchi. Pour cette « deuxième tranche de 10 000 », la moyenne s’établit donc à environ 1666 visites par mois, soit plus de 60% de progression ! J
     
    J’ignore où tout cela nous mènera, si tant est que ça doive nous mener quelque part, mais en tout cas un grand merci à vous tous. Je le disais déjà en janvier et je le redis aujourd’hui : ce blog est fait pour vous être utile, principalement dans votre apprentissage et votre découverte de Windows PowerShell, avec parfois (trop rarement ?) des petites digressions sur des sujets plus ou moins connexes. N’hésitez donc pas à me faire part de vos commentaires et de toute suggestion d’amélioration que vous pourriez avoir.
     
    Janel

    Un peu plus loin avec Word

    Dans mon précédent billet sur le pilotage de Microsoft Word à partir de PowerShell, je créais un document Word et j’y insérais du texte résultant d’une commandelette PowerShell avant d’enregistrer le document.
     
    Très bien me direz-vous, mais que peut-on faire à partir de PowerShell pour lire un document existant et l’analyser ?
     
    Ma foi vous répondrai-je, on peut faire beaucoup. Voici un exemple de script qui compte le nombre de mots, le nombre de phrases et le nombre de paragraphes présents dans un ou plusieurs documents Word :
     
    # measure-document.ps1
    #
    # Fournit des statistiques sur le(s) document(s) passé(s) par le pipeline.
    # Statistiques fournies:
    #   - Path       = Chemin du document
    #   - Name       = Nom du document
    #   - Size       = Taille du document (en octets)
    #   - Words      = Nombre de mots dans le document
    #   - Sentences  = Nombre de phrases dans le document
    #   - Paragraphs = Nombre de paragraphes dans le document
    #
    # Usage:
    #
    # dir *.doc | measure-document
    #
     
    # section exécutée avant le traitement du premier document:
    begin
    {
      # ouverture de l'application:
      $wordapp = new-object -com word.application
     
      # création de la variable à utiliser pour les paramètres facultatifs laissés vides:
      $m = [system.type]::missing
    }
     
    # section exécutée pour chaque document:
    process
    {
      # ouverture du document dans Word:
      $doc = $wordapp.documents.open($_.fullname,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m,$m)
     
      # récupération des mots, phrases et paragraphes:
      $words = $doc.words | where {$_.text -match "\w"} | select text
      $sentences = $doc.sentences | select text
      $paragraphs = $doc.paragraphs | select ID
     
      # construction de l'objet qui contiendra tous les résultats:
      $result = new-object PSObject
     
      # ajout des résultats:
      $result | add-member NoteProperty Path $doc.path
      $result | add-member NoteProperty Name $doc.name
      $result | add-member NoteProperty Size $_.length
      $result | add-member NoteProperty Words $words.length
      $result | add-member NoteProperty Sentences $sentences.length
      $result | add-member NoteProperty Paragraphs $paragraphs.length
     
      # fermeture du document:
      $doc.close()
     
      # affichage des résultats:
      $result
    }
     
    # section exécutée après le traitement du dernier document:
    end
    {
      # fermeture de l'application:
      $wordapp.quit()
      $wordapp = $null
    }
     
    Le script est assez largement auto-documenté, j’insisterai simplement sur sa construction en filtre avec les trois sections begin, process et end. Cette construction permet de traiter un à un les objets fournis par le pipeline, avec la possibilité d’initialiser le processus et de le conclure avec des tâches spécifiques. Vous trouverez un autre exemple de filtre avec out-voice que j’avais publié en mai 2006 sur ce même blog.
     
    Un mot également sur les paramètres facultatifs, illustrés dans ce script par la variable $m :
     
    De nombreuses méthodes exposées par les applications Office acceptent un nombre variable de paramètres, certains étant obligatoires et d’autres étant facultatifs. Mais s’il est possible en Visual Basic de ne passer que les paramètres qui nous intéressent et d’ignorer toute ou partie des paramètres facultatifs, malheureusement en C# et en PowerShell il faut passer tous les paramètres sans exception.
     
    Ainsi, dans mon script, la méthode Open() de l’objet $wordapp.documents accepte 16 paramètres. Bien que seul le premier soit obligatoire, il faut bien passer les 16 paramètres pour que l’appel à cette méthode soit considéré comme valide. Pour fournir une valeur aux 15 autres paramètres sans risquer de modifier leur valeur par défaut, on doit utiliser un type spécialement fourni par Microsoft à cette intention : [System.Type]::Missing. Dans mon script, pour simplifier la saisie je crée une variable $m associée à ce type que j’utiliserai en lieu et place de chaque paramètre que je ne compte pas utiliser.
     
    Je reviendrai également sur les paramètres facultatifs dans mon prochain billet sur Excel et PowerShell.
     
    Un dernier mot enfin pour répondre à une question que vous vous posez peut-être sur l’absence d’un compteur de pages dans mon script. Cette information pourrait être très utile dans une étude statistique sur l’ensemble des documents Word d’un poste ou d’un groupe de travail, par exemple pour anticiper sur des besoins d’impression.
     
    Malheureusement, bien qu’il existe une collection Pages documentée dans l’application Word, je n’ai pas trouvé comment l’utiliser pour obtenir le nombre de pages d’un document. Si vous avez la solution à ce petit problème, n’hésitez pas à la partager, et je me ferai une joie de mettre à jour mon script !
     
    A vous de jouer,
    Janel
    August 04

    Piloter Word à partir de PowerShell

    Premier billet d’une petite série sur l’interaction entre PowerShell et les applications Office, en partie démarrée sur le forum d’entraide du site PowerShell-Scripting.
     
    A plusieurs reprises la question a été posée de savoir comment envoyer des informations vers une application Office (Excel principalement, j’y reviendrai dans un prochain billet) à partir d’un script PowerShell.
     
    Dans ce premier billet je présenterai un usage très simple de Microsoft Word. L’exemple qui suit crée un document Word et lui envoie le contenu de la commandelette get-process. Le texte ainsi généré est formaté en Courier New, taille 10 et le document est sauvegardé sur disque. Il ne s’agit bien sûr que d’un exemple sans grand intérêt en tant que tel mais j’espère suffisamment illustratif pour inspirer des usages plus élaborés :
     
    $word = new-object -com word.application
    $word.visible = $true
    $doc = $word.documents.add()
    $doc.content.text = get-process | out-string
    $doc.content.font.name = "Courier New"
    $doc.content.font.size = 10
    $doc.saveas([ref]"c:\mesdocs\mes process.doc")
     
    L’essentiel de cet exemple repose sur l’accès à l’application par son objet COM, word.application. Une fois l’objet créé, on peut explorer ses méthodes et ses propriétés avec la commandelette get-member, et si l’on se trouve en manque d’information on peut recourir à l’aide en ligne disponible sur le site de Microsoft :
     
    Sur mon poste, j’utilise Office 2007 et je n’ai rien eu à faire de particulier pour accéder aux classes décrites dans la documentation ci-dessus. J’ignore si l’installation d’Office 2003 est différente, mais d’après mes échanges sur le forum de PowerShell-Scripting, il semble qu’avec Office 2003 les assemblies microsoft.office.interop – bien que fournies – ne soient pas installées par défaut. La procédure d’installation est décrite ici :
     

    Janel
    August 01

    Et un Provider OneNote pour PowerShell!

    Sapristi ! Je pensais justement ces derniers jours me remettre à utiliser OneNote pour organiser un peu mes notes. Si vous ne connaissez pas cette application, OneNote est un des derniers-nés de la suite Office permettant de saisir et d’organiser des notes sous plusieurs formes. Apparu avec Office 2003, il prend encore des galons avec Office 2007 en étendant notamment ses capacités de partage en réseau.
     
    Et voilà-t-y pas qu’un membre de l’équipe Office de Microsoft s’est mis en tête de développer un Provider pour PowerShell. Rappelons qu’avec un Provider, on peut accéder aux données d’une ressource en utilisant les mêmes commandes que pour l’accès à un disque et à ses fichiers. Sous PowerShell, il existe par défaut des Providers pour accéder non seulement aux disques mais aussi à la base de registre, aux magasins de certificats ou encore aux variables et aux alias. Vous l’aurez deviné, il est possible de développer des Providers additionnels pour accéder à d’autres types de données.
     
    Je n’ai pas encore testé ce Provider mais je tenais déjà à partager l’information avec vous. Le billet décrivant le Provider et fournissant installation et code source est ici :
     
     
    Je referai un billet dès que j’aurai pu faire quelques tests. Entre temps, n’hésitez pas à laisser un commentaire si vous voulez partager votre expérience avec ce Provider, ou si vous voulez faire connaître un autre Provider pour PowerShell.
     
    Janel