none
Mettre en forme la sortie d'une commande RRS feed

  • Question

  • Bonjour,

    Je débute avec powershell et je me tourne vers vous pour un petit problème avec un script powershell.

    Quand je fais un:

    Get-Process

    la sortie sur la console se présente sous forme de tableau bien propre.

    Maintenant je souhaite le mettre en forme avant de l'envoyer par mail. Je fais donc ceci:

    $Message = Get-Process $smtpServer = "127.0.0.1" $from = "toto@yahoo.fr" $to = "toto@gmail.com" $subject = "TEST" $body = "<html> <head></head> <body> <p>Bonjour,<br /> Voici le resultat de Get-Process<br /> $Message </p> </body> </html>" $body | Out-File -FilePath .\test.txt

    Send-MailMessage -smtpserver $smtpserver -from $from -to $to -subject $subject -body $body -bodyasHTML

    Mais contrairement a ce que je pensais j'ai ceci dans le txt et dans le mail:

    <html>
      <head></head>
         <body>
            <p>Bonjour,<br />
               Voici le resultat de Get-Process<br />
               System.Diagnostics.Process (AgentAntidote) System.Diagnostics.Process (AgentConnectix) System.Diagnostics.Process (AppleMobileDeviceService) System.Diagnostics.Process (armsvc) System.Diagnostics.Process (CefSharp.BrowserSubprocess) System.Diagnostics.Process (CefSharp.BrowserSubprocess) System.Diagnostics.Process (CefSharp.BrowserSubprocess) System.Diagnostics.Process (CompPkgSrv) System.Diagnostics.Process (conhost) System.Diagnostics.Process (conhost) System.Diagnostics.Process (conhost) System.Diagnostics.Process (csrss) System.Diagnostics.Process (csrss) System.Diagnostics.Process (ctfmon) System.Diagnostics.Process (dasHost) System.Diagnostics.Process (DeepL) System.Diagnostics.Process (dllhost) System.Diagnostics.Process (dllhost) System.Diagnostics.Process (dllhost) System.Diagnostics.Process (dwm) System.Diagnostics.Process (explorer) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (firefox) System.Diagnostics.Process (fontdrvhost) System.Diagnostics.Process (fontdrvhost) System.Diagnostics.Process (GoogleCrashHandler) System.Diagnostics.Process (GoogleCrashHandler64) System.Diagnostics.Process (Idle) System.Diagnostics.Process (igfxCUIService) System.Diagnostics.Process (igfxEM) System.Diagnostics.Process (igfxHK) System.Diagnostics.Process (iPodService) System.Diagnostics.Process (iTunesHelper) System.Diagnostics.Process (KillerNetworkService) System.Diagnostics.Process (LogiRegistryService) System.Diagnostics.Process (lsass) System.Diagnostics.Process (mDNSResponder) System.Diagnostics.Process (Memory Compression) System.Diagnostics.Process (mqsvc) System.Diagnostics.Process (MSIService) System.Diagnostics.Process (MsMpEng) System.Diagnostics.Process (NisSrv) System.Diagnostics.Process (nvcontainer) System.Diagnostics.Process (nvcontainer) System.Diagnostics.Process (nvcontainer) System.Diagnostics.Process (NVDisplay.Container) System.Diagnostics.Process (NVDisplay.Container) System.Diagnostics.Process (NVIDIA Web Helper) System.Diagnostics.Process (powershell) System.Diagnostics.Process (powershell_ise) System.Diagnostics.Process (PresentationFontCache) System.Diagnostics.Process (Registry) System.Diagnostics.Process (RuntimeBroker) System.Diagnostics.Process (RuntimeBroker) System.Diagnostics.Process (RuntimeBroker) System.Diagnostics.Process (RuntimeBroker) System.Diagnostics.Process (SearchApp) System.Diagnostics.Process (SearchFilterHost) System.Diagnostics.Process (SearchIndexer) System.Diagnostics.Process (SearchProtocolHost) System.Diagnostics.Process (SearchProtocolHost) System.Diagnostics.Process (SecurityHealthService) System.Diagnostics.Process (services) System.Diagnostics.Process (SettingSyncHost) System.Diagnostics.Process (SgrmBroker) System.Diagnostics.Process (ShellExperienceHost) System.Diagnostics.Process (sihost) System.Diagnostics.Process (smss) System.Diagnostics.Process (SMSvcHost) System.Diagnostics.Process (SMSvcHost) System.Diagnostics.Process (SMSvcHost) System.Diagnostics.Process (snmp) System.Diagnostics.Process (spoolsv) System.Diagnostics.Process (StartMenu) System.Diagnostics.Process (StartMenuExperienceHost) System.Diagnostics.Process (SteelSeriesEngine) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (svchost) System.Diagnostics.Process (SynTPEnh) System.Diagnostics.Process (SynTPEnhService) System.Diagnostics.Process (SynTPHelper) System.Diagnostics.Process (System) System.Diagnostics.Process (taskhostw) System.Diagnostics.Process (TCPSVCS) System.Diagnostics.Process (TeamViewer_Service) System.Diagnostics.Process (TextInputHost) System.Diagnostics.Process (tmGAInstall) System.Diagnostics.Process (unsecapp) System.Diagnostics.Process (UserOOBEBroker) System.Diagnostics.Process (wininit) System.Diagnostics.Process (winlogon) System.Diagnostics.Process (WmiPrvSE) System.Diagnostics.Process (wmpnetwk) System.Diagnostics.Process (WTSrv) System.Diagnostics.Process (WUDFHost) System.Diagnostics.Process (xTendUtility) System.Diagnostics.Process (xTendUtilityService)
            </p>
          </body>
    </html>
    

    Comment puis-je mettre en forme la sortie de cette commande?

    Merci de votre aide.

    jeudi 28 janvier 2021 18:51

Réponses

  • Bonjour Inrepublica

    J'explique.pour que tu comprennes bien et que tu évites cette erreur à l'avenir.

    Regardes le contenu de ta variable $Message

    $Message | Get-Member

    Tu vois les différentes propriétés (ou ScriptProperty) ? Tu vois à droite le type de données ? System.objet...

    C'est là que se situe le pb.

    Get-Process |    

    Sort-Object CPU -Descending |

        Select-Object -Property Name, ID, CPU -First 10

    Ci-dessus, j'ai trié et sorti uniquement les 10 1er process, et j'ai sélectionné 3 propriétés qui m'intéressent.

    Maintenant, si tu regardes les propriétés de ta variable

    $Message | gm  

    TypeName : Selected.System.Diagnostics.Process

    Name        MemberType   Definition

    ----        ----------   ----------

    Equals      Method       bool Equals(System.Object obj)

    GetHashCode Method       int GetHashCode()             

    GetType     Method       type GetType()                

    ToString    Method       string ToString()             

    CPU         NoteProperty System.Double CPU=2359,796875

    Id          NoteProperty int Id=22900                  

    Name        NoteProperty string Name=firefox   

    Mieux, on a des String et des Integers.

    Oui, mais ... c'est pô joli, il y a pleins de décimales. OK. On va faire un Custom Label

    $Message = Get-Process |    

    Sort-Object CPU -Descending |   

    Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},

                                      @{Label = "ID"  ; Expression = {$_.ID}},

                                       @{Label = "CPU" ; Expression ={($_.CPU).ToString("#.##")}}

    $Message = Get-Process |    

    Sort-Object CPU -Descending |

        Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},

                                         @{Label = "ID"  ; Expression = {$_.ID}},

                                          @{Label = "CPU" ; Expression ={"{0:N2}" -f ($_.CPU)}}

    $Message = Get-Process |
        Sort-Object CPU -Descending |
        Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},
                                          @{Label = "ID"  ; Expression = {$_.ID}},
                                          @{Label = "CPU" ; Expression ={[Math]::Round($_.CPU,2)}}

    Les 3 solutions affichent le même résultat, mais attention, il y a quand même une différence.

    Dans le 1er cas, j'ai transformé un nombre en texte et je l'ai formaté comme une chaine. Je perds tout ce qui trainait derrière.

    Dans le second cas, j'ai utilisé l'opérateur -f en indiquant que je voulais un nombre avec 2 décimales.

    Dans le dernier cas, j'ai conservé un nombre, c'est juste un arrondi avec 2 décimales en sortie, mais le vrai nombre non tronqué est bien là.

    Tout dépend,  si tu dois réutiliser plus loin le résultat.

    Conseil : pour les cmdlets qui ont de nombreux paramètres à passer (obligatoire ou pas), et c'est le cas pour Send-MailMessage, penses à utiliser un Splat, ça rend tes lignes plus lisibles et plus faciles à modifier.

    $Body = "<html>
      <head></head>
         <body>
            <p>Bonjour,<br />
               Voici le resultat de Get-Process<br />
               $Message
            </p>
          </body>
    </html>"
    
    $MailParams =@{
        smtpServer = "127.0.0.1"
        from       = "toto@yahoo.fr"
        to         = "toto@gmail.com"
        subject    = "TEST"
        body       = $Body
        BodyAsHTML = $true
        }
    
    Send-MailMessage @MailParams

    Ci -dessous, une sortie Zolie tout plein (enfin tout est question de goût)

    # Ici je transforme la variable en html mais comme fragment $Message = $Message | ConvertTo-Html -Fragment # Ici je définis une feuille de style interne ... pour que cela soit zoli $Head = @" <style> body {font-family: "Arial";font-size: 8pt;color: #4C607B} th, td {border: 1px solid #e57300;border-collapse: collapse;padding: 5px} th {font-size: 1.2em;text-align: left;background-color: #003366;color: #ffffff} td {color: #000000} .even { background-color: #ffffff} .odd { background-color: #bfbfbf} </style> "@ # corps du mail $Body = @" <html> <body> <p>Bonjour,<br /> Voici le resultat de Get-Process<br /> <p>$Message</p> </p> </body> </html> "@ $FinalMail = ConvertTo-HTML -Head $Head -Body $Body -PostContent "Mail généré le : $(Get-Date -Format "dddd dd-MM-yyyy à hh:mm:ss")" $MailParams =@{ smtpServer = "127.0.0.1" from = "toto@yahoo.fr" to = "toto@gmail.com" subject = "TEST" body = $mail BodyAsHTML = $true } # Ca c'était juste pour voir le résultat $FinalMail | Out-File C:\temp\a.htm ii C:\temp\a.htm

    # et l'envoi par mail qui utilise le splat Send-MailMessage @MailParams

    Résumons :

    • Ta variable ne s'affichait pas car System.object
    • Ta variable qui est un tableau doit être convertie en html comme un fragment
    • On ajoute une feuille de style interne en utilisant une Here-String... pour rendre joli
    • On créé le body en utilisant une Here-String ... as you want
    • On assemble Style + body + et on ajoute en passant un PostContent au mail
    • Et puis on envoie le mail en passant en paramètre un splat avec toutes les propriétés à passer

    L'intéret de tout cela est que maintenant si tu veux changer ton script de larges portions ne sont pas à modifier. 

    Exemple :

    Tu ajoutes une autre query que tu poses en var comme pour les process et transforme en fragment html. Ajout

    Tu modifies le contenu de ta variable $Body : modification mineure

    ... et le reste : rien. Code reuse !

    "Have fun with Powershell"

    Cordialement

    Olivier

    P.S. : envoyer chez google sans être authentifié, ça ne va pas le faire.


    vendredi 29 janvier 2021 15:16
  • J'ajoute juste une petite correction il faut ajouter un pipe Out-String après le convert to HTML sinon il y a une erreur:

    $FinalMail = ConvertTo-HTML -Head $Head -Body $Body -PostContent "Mail généré le : $(Get-Date -Format "dddd dd-MM-yyyy à hh:mm:ss")" | Out-String

    • Marqué comme réponse Inrepublica mardi 30 mars 2021 15:32
    mardi 30 mars 2021 15:32

Toutes les réponses

  • Une première piste 

    $Message =get-process | ConvertTo-Html

    Deuxieme piste

    $message=get-process |  out-string


    jeudi 28 janvier 2021 19:31
  • Bonjour Inrepublica

    J'explique.pour que tu comprennes bien et que tu évites cette erreur à l'avenir.

    Regardes le contenu de ta variable $Message

    $Message | Get-Member

    Tu vois les différentes propriétés (ou ScriptProperty) ? Tu vois à droite le type de données ? System.objet...

    C'est là que se situe le pb.

    Get-Process |    

    Sort-Object CPU -Descending |

        Select-Object -Property Name, ID, CPU -First 10

    Ci-dessus, j'ai trié et sorti uniquement les 10 1er process, et j'ai sélectionné 3 propriétés qui m'intéressent.

    Maintenant, si tu regardes les propriétés de ta variable

    $Message | gm  

    TypeName : Selected.System.Diagnostics.Process

    Name        MemberType   Definition

    ----        ----------   ----------

    Equals      Method       bool Equals(System.Object obj)

    GetHashCode Method       int GetHashCode()             

    GetType     Method       type GetType()                

    ToString    Method       string ToString()             

    CPU         NoteProperty System.Double CPU=2359,796875

    Id          NoteProperty int Id=22900                  

    Name        NoteProperty string Name=firefox   

    Mieux, on a des String et des Integers.

    Oui, mais ... c'est pô joli, il y a pleins de décimales. OK. On va faire un Custom Label

    $Message = Get-Process |    

    Sort-Object CPU -Descending |   

    Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},

                                      @{Label = "ID"  ; Expression = {$_.ID}},

                                       @{Label = "CPU" ; Expression ={($_.CPU).ToString("#.##")}}

    $Message = Get-Process |    

    Sort-Object CPU -Descending |

        Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},

                                         @{Label = "ID"  ; Expression = {$_.ID}},

                                          @{Label = "CPU" ; Expression ={"{0:N2}" -f ($_.CPU)}}

    $Message = Get-Process |
        Sort-Object CPU -Descending |
        Select-Object -First 10 -Property @{Label = "Nom" ; Expression = {$_.Name}},
                                          @{Label = "ID"  ; Expression = {$_.ID}},
                                          @{Label = "CPU" ; Expression ={[Math]::Round($_.CPU,2)}}

    Les 3 solutions affichent le même résultat, mais attention, il y a quand même une différence.

    Dans le 1er cas, j'ai transformé un nombre en texte et je l'ai formaté comme une chaine. Je perds tout ce qui trainait derrière.

    Dans le second cas, j'ai utilisé l'opérateur -f en indiquant que je voulais un nombre avec 2 décimales.

    Dans le dernier cas, j'ai conservé un nombre, c'est juste un arrondi avec 2 décimales en sortie, mais le vrai nombre non tronqué est bien là.

    Tout dépend,  si tu dois réutiliser plus loin le résultat.

    Conseil : pour les cmdlets qui ont de nombreux paramètres à passer (obligatoire ou pas), et c'est le cas pour Send-MailMessage, penses à utiliser un Splat, ça rend tes lignes plus lisibles et plus faciles à modifier.

    $Body = "<html>
      <head></head>
         <body>
            <p>Bonjour,<br />
               Voici le resultat de Get-Process<br />
               $Message
            </p>
          </body>
    </html>"
    
    $MailParams =@{
        smtpServer = "127.0.0.1"
        from       = "toto@yahoo.fr"
        to         = "toto@gmail.com"
        subject    = "TEST"
        body       = $Body
        BodyAsHTML = $true
        }
    
    Send-MailMessage @MailParams

    Ci -dessous, une sortie Zolie tout plein (enfin tout est question de goût)

    # Ici je transforme la variable en html mais comme fragment $Message = $Message | ConvertTo-Html -Fragment # Ici je définis une feuille de style interne ... pour que cela soit zoli $Head = @" <style> body {font-family: "Arial";font-size: 8pt;color: #4C607B} th, td {border: 1px solid #e57300;border-collapse: collapse;padding: 5px} th {font-size: 1.2em;text-align: left;background-color: #003366;color: #ffffff} td {color: #000000} .even { background-color: #ffffff} .odd { background-color: #bfbfbf} </style> "@ # corps du mail $Body = @" <html> <body> <p>Bonjour,<br /> Voici le resultat de Get-Process<br /> <p>$Message</p> </p> </body> </html> "@ $FinalMail = ConvertTo-HTML -Head $Head -Body $Body -PostContent "Mail généré le : $(Get-Date -Format "dddd dd-MM-yyyy à hh:mm:ss")" $MailParams =@{ smtpServer = "127.0.0.1" from = "toto@yahoo.fr" to = "toto@gmail.com" subject = "TEST" body = $mail BodyAsHTML = $true } # Ca c'était juste pour voir le résultat $FinalMail | Out-File C:\temp\a.htm ii C:\temp\a.htm

    # et l'envoi par mail qui utilise le splat Send-MailMessage @MailParams

    Résumons :

    • Ta variable ne s'affichait pas car System.object
    • Ta variable qui est un tableau doit être convertie en html comme un fragment
    • On ajoute une feuille de style interne en utilisant une Here-String... pour rendre joli
    • On créé le body en utilisant une Here-String ... as you want
    • On assemble Style + body + et on ajoute en passant un PostContent au mail
    • Et puis on envoie le mail en passant en paramètre un splat avec toutes les propriétés à passer

    L'intéret de tout cela est que maintenant si tu veux changer ton script de larges portions ne sont pas à modifier. 

    Exemple :

    Tu ajoutes une autre query que tu poses en var comme pour les process et transforme en fragment html. Ajout

    Tu modifies le contenu de ta variable $Body : modification mineure

    ... et le reste : rien. Code reuse !

    "Have fun with Powershell"

    Cordialement

    Olivier

    P.S. : envoyer chez google sans être authentifié, ça ne va pas le faire.


    vendredi 29 janvier 2021 15:16
  • Super merci beaucoup pour votre aide précieuse!!!
    lundi 1 février 2021 16:55
  • J'ajoute juste une petite correction il faut ajouter un pipe Out-String après le convert to HTML sinon il y a une erreur:

    $FinalMail = ConvertTo-HTML -Head $Head -Body $Body -PostContent "Mail généré le : $(Get-Date -Format "dddd dd-MM-yyyy à hh:mm:ss")" | Out-String

    • Marqué comme réponse Inrepublica mardi 30 mars 2021 15:32
    mardi 30 mars 2021 15:32