vendredi 13 février 2009

Création de fiche serveur avec Word 2007 et PowerShell (Partie 3)

La partie précédente de cet article se trouve ICI !

Nous avons donc à ce stade récupéré les informations matérielles et logicielles d’une machine distante.

Nous allons donc maintenant créer un document Word 2007 à la main. Pourquoi à la main ? Parce que notre script sera capable de rafraîchir certaines « zones » de notre document. De ce fait, il s’adaptera au template imposé par notre société !

Les « zones » dans lesquelles PowerShell écrira sont en réalité appelées « Contrôles de contenu » et se trouvent dans l’onglet « Développeur » de Word 2007 puis dans le groupe « Contrôles ». Comme dans l’image ci-dessous :


Ainsi, pour chaque information récupérée dans l’article précédent, nous allons insérer dans notre document un contrôle de contenu.

Lorsqu’un contrôle de contenu est inséré, nous pouvons lui donner un nom et nous allons le faire ! Cela permettra à notre script PowerShell qui écrira dans le document Word de savoir dans quel contrôle de contenu écrire en fonction de l’information récupérée sur notre machine distante.


Dans la partie précédente de l’article, nous avons écrit les fonctions Get-ComputerHardware et Get-ComputerSoftware. Si vous avez regardé de prêt ces fonctions, elle retourne un objet dont les propriétés sont les informations récupérées sur la machine distante.

L’astuce est donc de donner à nos contrôles de contenu les mêmes noms que les propriétés de nos objets retournés par les deux fonctions citées précédemment !

Une fois le document créé aux couleurs de notre société et peuplé de nos contrôles de contenu… nous pouvons créer le script qui va rafraîchir ce document : c'est-à-dire écrire dans les contrôles de contenu !

Pour cela, dans un nouveau fichier nommé « Generate-ServerForm.ps1 » nous allons écrire :

  1. function Refresh-OpenXmlDocument($strDocPath, $strComputer)
  2. {
  3.     $objDoc = Get-OpenXmlDocument -Path $strDocPath -SuppressBackups
  4.     if ($objDoc -eq $null) { return }

  5.     $objUri = New-Object Uri('/word/document.xml', [UriKind]::Relative)
  6.     $objPart = $objDoc.Package.GetPart($objUri)

  7.     $script:objXmlDoc = New-Object Xml.XmlDocument
  8.     $script:objXmlDoc.Load($objPart.GetStream())

  9.     $objNsMgr = New-Object Xml.XmlNamespaceManager($objXmlDoc.NameTable)
  10.     $strURL = 'http://schemas.openxmlformats.org'
  11.     $objNsMgr.AddNamespace('w', "$strURL/wordprocessingml/2006/main")

  12.     $objNodes = $script:objXmlDoc.DocumentElement.GetElementsByTagName('w:sdt')
  13.     $objInfo = Get-ComputerInfo $strComputer

  14.     foreach ($objNode in $objNodes) {
  15.         $objN = $objNode.SelectSingleNode('w:sdtPr', $objNsMgr)
  16.         $strAlias = Get-OpenXmlContentCtrlAlias $objN $objNsMgr
  17.         if ($strAlias -ne '') {
  18.             $objProperty = $objInfo | Get-Member -Name $strAlias
  19.             if ($objProperty -ne $null) {
  20.                 $objN = $objNode.SelectSingleNode('w:sdtContent', $objNsMgr)
  21.                 switch -regex ($objInfo.$strAlias.GetType().Name) {
  22.                     '\[\]$' {
  23.                         Set-OpenXmlTable $objN $objNsMgr $objInfo.$strAlias
  24.                     }
  25.                     default {
  26.                         Set-OpenXmlText $objN $objNsMgr $objInfo.$strAlias
  27.                     }
  28.                 }
  29.             }
  30.         }
  31.     }

  32.     $script:objXmlDoc.Save($objPart.GetStream())
  33.     $objDoc.Close()
  34. }

Nous allons essayer d’analyser cette première fonction. Pour commencer… son but est d’écrire dans les contrôles de contenu d’un document Word 2007. Elle prend deux arguments ; le premier : le chemin vers notre template précédemment créé et le second, le nom de la machine dont nous devons récupérer les informations pour faire notre fiche.

Ensuite, nous allons mettre un peu les mains dans le format OpenXML !

La première chose qu’on remarque est l’appel à la Cmdlet Get-OpenXMLDocument. Elle provient des PowerTools. Vous devez donc avoir installé ces outils comme décrit dans cet article !

Nous allons faire une petite parenthèse sur le format OpenXML : un fichier Office 2007 est en réalité un fichier .ZIP renommé en .DOCX, XLSX ou PPTX ! Si vous renommez le fichier avec l’extension .ZIP et que vous le décompressez vous aurez une arborescence de fichiers.

Pour Word, vous aurez notamment un fichier « /word/document.xml » qui n’est rien d’autre que le contenu de notre document Word 2007 au format XML ! C’est précisément ce fichier XML que nous récupérons pour le manipuler. Fin de la parenthèse sur le format OpenXML !

Nous allons donc nous déplacer dans ce fichier XML en repérant nos contrôles de contenu dont la balise est : « w:sdt »

  1. $script:objXmlDoc.DocumentElement.GetElementsByTagName('w:sdt')

Remarque : nous avons écrit $script:objXmlDoc afin de rendre visible notre variable dans tout le script.

Nous pouvons donc naviguer de contrôles de contenu en contrôles de contenu dans notre document en repérant ces balises ! Ensuite, pour chaque contrôle de contenu, nous devons récupérer son nom qui je vous le rappelle est aussi le nom d’une propriété de l’objet retourné par nos fonctions récupérant les informations d’une machine. Dans notre exemple, nous avons utilisé une fonction nommée Get-ComputerInfo. Cette fonction retourne un objet fusionnant le retour de Get-ComputerHardware et Get-ComputerSoftware.

Pour cela vous pouvez rajouter cette fonction dans notre module précédemment créé :

  1. function Merge-Object($objSource, $objDest)
  2. {
  3.     $objSource | Get-Member -MemberType NoteProperty | % {
  4.         Add-Property $objDest $_.Name $objSource.($_.Name)
  5.     }
  6.     
  7.     return $objDest
  8. }

  9. function Get-ComputerInfo($strComputer)
  10. {
  11.     $objHardware = Get-ComputerHardware $strComputer
  12.     $objSoftware = Get-ComputerSoftware $strComputer
  13.     
  14.     return (Merge-Object $objHardware $objSoftware)
  15. }

Remarque : la fonction Merge-Objet fusionne les propriétés que nous avons rajoutées sur nos objets !

Biensûr, il faut modifier dans ce cas la fin de notre module pour rendre visible cette nouvelle fonction :

  1. Export-ModuleMember -Function 'Get-ComputerHardware',
  2.                               'Get-ComputerSoftware',
  3.                               'Get-ComputerInfo'

Mais nous avons oublié une petite chose ! Nous devons dire à notre nouveau script qu’il doit utiliser notre module ! Nous le faisons grâce à la Cmdlet Import-Module que nous ajoutons au tout début de notre script :

  1. Import-Module .\Computer_Info.psm1

Remarque : ici, notre module se situe dans le même répertoire que notre script.

Maintenant que nous avons tous les éléments, pour chaque contrôle de contenu nous récupérons son nom avec la fonction Get-OpenXmlContentCtrlAlias :

  1. function Get-OpenXmlContentCtrlAlias($objNode, $objNsMgr)
  2. {
  3.     $strAlias = ''

  4.     $objNode = $objNode.SelectSingleNode('w:alias', $objNsMgr)
  5.     $strAlias = $objNode.Attributes | where-Object { $_.Name -eq 'w:val'}
  6.     if ($strAlias -ne $null) { $strAlias = $strAlias.Value }
  7.     else { $strAlias = '' }
  8.     
  9.     return $strAlias.Trim()
  10. }

Puis, si les données que nous devons écrire sont contenues dans un tableau nous appelons Set-OpenXmlTable sinon nous appelons Set-OpenXmlText !

Comme nous avons bien avancé, nous allons faire une petite pause ! Je vous donne rendez-vous au prochain article pour la suite de notre petite aventure !

Aucun commentaire:

Enregistrer un commentaire