Jacques's profilejanelPhotosBlogLists Tools Help
    September 28

    Je redirige les objets PowerShell dans un fichier Excel

    Au cours de l’été j’avais commencé une série de billets sur quelques techniques de base pour interagir avec Word à partir de PowerShell. Voici un script montrant une technique simple d’interaction avec Excel. Ce script, baptisé out-excel, récupère les objets émis par le pipeline et les sauvegarde dans un fichier Excel.
     
    La manipulation repose sur un format intermédiaire : le format CSV. PowerShell permet d’exporter une collection d’objets au format CSV avec la commandelette standard export-csv, et il se trouve que ce format est reconnu par Excel. Je peux donc :
     
    • Exporter les objets émis par le pipeline dans un fichier temporaire au format CSV
    • Ouvrir ce fichier temporaire dans Excel
    • Sauvegarder le fichier au format Excel
    • Effacer le fichier temporaire
    Il est possible que vous ayez des problèmes à l’exécution de ce script. Notamment :
     
    1. Si vous utilisez Excel 2007 et que vous n’avez pas encore piloté Office 2007 via COM, vous devrez très certainement commencer par installer les PIA (Primary Interop Assemblies). Voir mon premier billet sur le sujet pour plus d’infos.
    2. Si votre système est réglé avec des paramètres régionaux français, il est possible que vous ayez l’erreur suivante : Exception calling "OpenText" with "18" argument(s): "Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD))". La seule solution que je connaisse pour remédier à cela, c’est de passer votre système en paramètres « Anglais (Etats-Unis) ». Il faudra ouvrir une nouvelle session PowerShell pour pouvoir récupérer les nouveaux paramètres. Si vous avez trouvé mieux, je suis preneur !
    3. Si vous n’avez pas l’erreur précédente, vous aurez peut-être un souci avec le délimiteur. Par défaut dans un système paramétré en français, le « séparateur de listes » est un point-virgule. Or, la commandelette export-csv de PowerShell utilise la virgule, séparateur de listes standard dans les paramètres US. J’ai conçu mon script pour qu’il indique à Excel d’utiliser la virgule, mais n’ayant pas pu tester la situation d’un poste en français qui accepterait d’ouvrir le fichier (problème #2 ci-dessus), je ne sais pas si ça marche quand le système est paramétré pour utiliser le point-virgule. A vous de voir et de me dire le cas échéant.
    Quoi qu’il en soit, voici le script :
     
    # out-excel.ps1
    #
    # Auteur: janel
    # Date: 28/09/2007
    #
    # Redirige les objets émis par le pipeline dans un fichier Excel
    #
    # Usage:
    #
    # <commande> | out-excel [-filename] <fichier> [-force] [-autofit] [-header]
    #
    # -filename indique le nom du fichier Excel à utiliser
    # -force spécifie qu'un fichier existant du même nom sera écrasé
    # -autofit ajuste automatiquement la taille des colonnes à leur contenu
    # -header met la première ligne en gras et bloque son affichage
    #
    # Exemple:
    #
    # get-process | select name,company,path,{$_.mainmodule.fileversion} | out-excel process.xls -force -h -a
    #
    # ... crée un fichier process.xls dans le répertoire courant avec les informations
    # souhaitées sur les processus en cours d’exécution.
    #
    param (
      [String]$filename,
      [switch]$force,
      [switch]$autofit,
      [switch]$header
    )
     
    # ajouter le répertoire en cours au nom de fichier si non précisé:
    if (!(split-path $filename)) {$filename = join-path $pwd.path $filename}
     
    # créer un fichier temporaire pour stocker les données au format CSV:
    $tempfile = [System.IO.Path]::GetTempFileName()
    $data = @($input)
    $data | export-csv $tempfile -notypeinformation
     
    # utiliser l'objet COM Excel:
    $excel = new-object -com Excel.Application
     
    # ouvrir le fichier CSV dans Excel:
    $xlDelimited = [Microsoft.Office.Interop.Excel.xlTextParsingType]::xlDelimited
    $xlTextQualifierNone = [Microsoft.Office.Interop.Excel.XlTextQualifier]::xlTextQualifierNone
    $m = [System.Type]::Missing
    $csv = $excel.Workbooks.OpenText($tempfile, $m, 1, $xlDelimited, $xlTextQualifierNone, $m, $m, $m, $true, $m, $m, $m, $m, $m, $m, $m, $m, $m)
     
    # appliquer les modifications optionnelles:
    $workbook = $excel.ActiveWorkbook
    if ($autofit) {[void]$workbook.ActiveSheet.Columns.AutoFit()}
    if ($header)
    {
      $workbook.ActiveSheet.Rows.Item(1).Font.Bold = $true
      $workbook.Activate()
      $excel.ActiveWindow.SplitRow = 1
      $excel.ActiveWindow.FreezePanes = $true
    }
     
    # supprimer un fichier du même nom s'il existe:
    if ($force) {del $filename -ea SilentlyContinue > $null}
     
    # sauvegarder le fichier au format Excel:
    $xlWorkbookNormal = [Microsoft.Office.Interop.Excel.xlFileFormat]::xlWorkbookNormal
    $workbook.SaveAs($filename, $xlWorkbookNormal)
    remove-item $tempfile
     
    # faire le ménage:
    $excel.WindowState = "xlMinimized"
    $excel.visible = $true
    stop-process @(get-process | where {$_.MainWindowHandle -eq $excel.Hwnd})[0].Id
     
    # fin du script
     
     
    Commentaires bienvenus !
     
    Janel
    September 19

    Concours PowerShell-Scripting.com et ping en boucle

    Avec tout le travail que j’ai pour la rentrée des classes, j’avais oublié de vous signaler le lancement d’un concours de scripts sur www.powershell-scripting.com !
     
    Toutes les informations sont ici : [CONCOURS] Les règles
     
    Evidemment, je me suis empressé d’y participer (et je n’ai pas fini, le concours étant ouvert jusqu’au 31 décembre de cette année). Vous retrouverez dans le même forum que les règles ci-dessus mes premières contributions. Je poste également ici ma dernière en date, qui permet d’avoir un affichage récurrent sur une liste d’ordinateurs et leur statut réseau (basé sur un simple ping).
     
    --- début de script
     
    # get-status.ps1
    #
    # Auteur: janel
    # Date: 19/09/2007
    #
    # Affiche une liste d'ordinateurs avec leur adresse IP et leur statut réseau.
    # La liste est rafraichie à un intervalle déterminé par l'utilisateur.
    #
    # Syntaxe:
    #
    # get-status [-computerlist] <liste d'ordinateurs> [[-interval] <intervalle en s.>]
    #
    # Le paramètre interval a une valeur de 10 secondes par défaut.
    # Un appui sur CTRL+C interrompt le script (après l'affichage des serveurs).
    # Un appui sur n'importe quelle autre touche abrège immédiatement l'attente.
    #
    # Exemples:
    #
    # get-status server01,server02,server03 -interval 30
    #
    # ... affiche toutes les 30 secondes le statut pour server01, server02 et server03.
    #
    # get-status (get-content serveurs.txt)
    #
    # ... affiche toutes les 10 secondes le statut des serveurs contenus dans serveurs.txt.
    #
     
    param ($computerlist, [int]$interval = 10)
     
    # créer un tableau de correspondance entre les valeurs de retour et leur signification :
    # (source: http://msdn2.microsoft.com/fr-fr/library/aa394350.aspx)
    $pingstatusref = @{}
    $pingstatusref[0] = "Success"
    $pingstatusref[11001] = "Buffer Too Small"
    $pingstatusref[11002] = "Destination Net Unreachable"
    $pingstatusref[11003] = "Destination Host Unreachable"
    $pingstatusref[11004] = "Destination Protocol Unreachable"
    $pingstatusref[11005] = "Destination Port Unreachable"
    $pingstatusref[11006] = "No Resources"
    $pingstatusref[11007] = "Bad Option"
    $pingstatusref[11008] = "Hardware Error"
    $pingstatusref[11009] = "Packet Too Big"
    $pingstatusref[11010] = "Request Timed Out"
    $pingstatusref[11011] = "Bad Request"
    $pingstatusref[11012] = "Bad Route"
    $pingstatusref[11013] = "TimeToLive Expired Transit"
    $pingstatusref[11014] = "TimeToLive Expired Reassembly"
    $pingstatusref[11015] = "Parameter Problem"
    $pingstatusref[11016] = "Source Quench"
    $pingstatusref[11017] = "Option Too Big"
    $pingstatusref[11018] = "Bad Destination"
    $pingstatusref[11032] = "Negotiating IPSEC"
    $pingstatusref[11050] = "General Failure"
     
    # se préparer à intercepter CTRL+C :
    [System.Console]::TreatControlCAsInput = $true
     
    # mémoriser la position de départ pour l'affichage du statut :
    $startposition = $host.UI.RawUI.CursorPosition
     
    while ($true)
    {
      # effacer les lignes :
      $host.UI.RawUI.CursorPosition = $startposition
      " " * $host.UI.RawUI.WindowSize.Width * $computerlist.Length
     
      # revenir à la position de départ :
      $host.UI.RawUI.CursorPosition = $startposition 
     
      # parcourir la liste des ordinateurs :
      $computerlist | foreach `
      {
        # "pinger" l'ordinateur :
        $pingstatus = get-wmiobject Win32_PingStatus -filter ("Address='" + $_ + "'")
     
        # afficher le nom et l'adresse IP de l'ordinateur :
        write-host $pingstatus.Address.PadRight(16," ") -nonewline
        write-host $pingstatus.ProtocolAddress.PadRight(16," ") -nonewline
     
        # déterminer le texte à afficher pour le statut :
        $statustext = $pingstatusref[[int]$pingstatus.StatusCode]
        (!$pingstatus.ProtocolAddress) -and ($statustext = "Request could not find host") > $null
     
        # déterminer la couleur d'affichage pour le statut (vert si 0, rouge sinon) :
        $statuscolor = "green"
        ($pingstatus.StatusCode -or !$pingstatus.ProtocolAddress) -and ($statuscolor = "red") > $null
     
       # afficher le statut :
        write-host $statustext -foreground $statuscolor
      # fin du foreach
     
      # attendre l'intervalle demandé :
      $endtime = (get-date).AddSeconds($interval)
      while ((get-date) -le $endtime)
      {
        # lire les entrées clavier :
        if ([System.Console]::KeyAvailable)
        {
          $key = [System.Console]::ReadKey($true)
     
          # intercepter CTRL+C :
          if (($key.Modifiers -band [System.ConsoleModifiers]"control") -and ($key.Key -eq "C"))
          {
            # effacer les lignes :
            $host.UI.RawUI.CursorPosition = $startposition
            " " * $host.UI.RawUI.WindowSize.Width * $computerlist.Length
     
            # revenir à la position de départ :
            $host.UI.RawUI.CursorPosition = $startposition
     
            # interrompre le script :
            exit
          }  # fin du if (($key.Modifiers ...
     
          # si autre touche, abréger l'attente :
          else
          {
            break
          }  # fin du else
        }  # fin du if ([System.Console]::KeyAvailable)
      }  # fin du while ((get-date) -le $endtime)
    # fin du while ($true)
     
    --- fin de script
     
    J’espère que ce script vous sera d’une quelconque utilité, ou au moins qu’il vous aura apporté une illustration intéressante de quelques techniques assez rarement utilisées (lecture du clavier par les API .NET, interception du CTRL+C, positionnement de l’affichage dans la console PowerShell, etc).
     
    Bon vent (frais) !
     
    Janel
    September 03

    Conférence ITIL / itSMF France le 16 octobre 2007

    Le 16 octobre prochain se tiendra au Palais des Congrès de Paris la 5e Conférence annuelle de l’itSMF France pour la promotion et l’enrichissement des savoirs autour d’ITIL. Vous pouvez encore vous inscrire, et si c’est déjà fait vous pouvez consulter l’agenda de la journée :
     
     
    Pour l’occasion, Microsoft France, sponsor Diamond d’itSMF, a mis à jour sa page d’introduction à ITIL :
     
     
    Détail amusant, j’ai également (re-)découvert sur le blog de Stéphane Papp le lien vers la présentation que j’avais faite à la conférence de l’année dernière :
     
     
    Tant de choses se sont passées depuis… Un an après, il y aurait matière à faire un point sur l’avancée de nos travaux internes :
     
    • ·         Le plan continu d’amélioration des services (Continual Service Improvement Program) est maintenant en place et commence à donner ses premiers résultats ;
    • ·         La deuxième version de notre Catalogue de Services est en cours d’élaboration avec notamment l’intégration de notre offre applicative interne ;
    • ·         Notre plateforme de Scorecard pour le suivi des performances des services évolue avec le déploiement de PerformancePoint Server ;
    • ·         Etc.
    Mais faute de temps je n’ai pas prévu de faire une présentation cette année. J’essaierai malgré tout d’être présent sur le stand de Microsoft, alors n’hésitez pas à venir échanger avec nous. Vous trouverez plus de détails sur la présence de Microsoft à la Conférence ici :
     
     
    Bon ITIL,
    Janel