none
Outlook item.htmlbody in HTML object wandeln und tags suchen RRS feed

  • Frage

  • Moin,
    ich lese mit einem PS script eine Outlook Mailbox und PST aus und speichere unter anderem die msg Dateien auf Disk.
    Diese msg Dateien öffne ich mit einen anderen script und nutze .CreateitemFromTemplate um ein Outlook Objekt zu erstellen.
    Nun habe ich Zugriff auf .body und .htmlbody.
    Aus dem Mail Body möchte ich all URLs extrahieren.
    Das mache ich aktuell mit regex. Klappt auch ganz gut soweit, aber einige Links werden nicht korrekt erfasst.
    Deshalb möchte ich den htmlbody in ein HTML object wandeln und dann mit .getElementsByTagName(‘a’) auf die Links zugreifen.
    Versucht habe ich das mit new-object -COM HTMLFile aber es klappt nicht.

    Kann mit jemand sagen, wie ich aus einem string mit HTML Daten ein HTML Objekt erstellen kann auf das ich dann alle HMTL Methoden anwenden kann?

    Danke und Gruß
    Michael


    • Bearbeitet deroppi Freitag, 12. Dezember 2014 13:23 korrigiert
    Freitag, 12. Dezember 2014 07:11

Antworten

  • Vielen Dank Peter!
    Nachdem ich recht viel gesucht und probiert habe, ist mir eine einfachere Lösung gelungen.
    Von dem HtmlAgilityPack hatte ich gelesen, wollte es aber nicht einsetzen.
    So wie unten gezeigt funktioniert es in PS v4 und ist ziemlich mächtig.

    Mein Regex Lösung zur Linksuche muss ich auch noch nutzen, da ja nicht alle Emails als HTML kommen.
    Also suche ich nun zuerst im htmlbody und wenn der leer ist, dann such ich im Text.

    Suche Links und Bilder in einem HTML String:

    $htmlDoc= New-Object -com "HTMLFILE"
    
    
    $page = @'
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Test Dokument</title>
    </head>
    <body>
    <p>Hallo Welt!</p>
    <p><a href="HTTP://www.Microsoft.de">Ich bin Link! </a></p>
    <p><a href="http://www.PowerShell-Group.eu">Noch Linker!</a></p>
    <p><img src="http://www.powershell-group.eu/wp-content/uploads/2013/10/Logo-Gross2.png">
    <p>
    
    <a href="http://google
    
    .de">Ich bin ein kaputter Link, wenn als Text geparsed<
    
    /a
    >
    
    </body>
    </html>
    '@
    
    $htmlDoc.IHTMLDocument2_write($page)
    
    write-host Links
    $htmlDoc.IHTMLDocument2_links | select -expandproperty "href"
    
    write-host Images
    $htmlDoc.IHTMLDocument2_images | select -expandproperty "src"
    
    [void]$htmlDoc.close

    Der Vollständigkeit halber hier noch die Suche im Text mit Filter für bestimmte Endungen.
    Den regex Ausdruck habe ich aus dem Internet, es gibt viele Ansätze, dieser hier lief bei mir am Besten, mit Ausnahme von Links die in mehrere Zeilen aufgebrochen waren.

    # extracting URLs from text
    
    $ExtFilter = "", "txt","jpg", "jpeg","gif","png","bmp","bin", "wmv" ,"dtd"
    
    $text= @'
    Das ist ein Text in dem eine Link enthalten ist.
    Um ganz viel Geld zu bekommen klicken sie hier: https://www.google.de/?gws_rd=ssl#q=ganz+viel+Geld !!!
    Klicken sie sofort und ohne zu denken.
    '@
    
    $regex="(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?"
    $URLs=[regex]::matches($Text, $regex,  [system.Text.RegularExpressions.RegexOptions]::Singleline)     
    Foreach ($URL in $URLs) {
        
        $split=[string]$URL
        $split=$split.split(".")
                       
        if (($ExtFilter -notcontains $split[-1]) -and (@($split).length -gt 1)) {
            write-host $URL
        }    
    }

    Ich bin neu bei PS, also seht mir bitte irgendwelche grauenhaften Konstrukte nach.



    • Bearbeitet deroppi Freitag, 12. Dezember 2014 16:32
    • Als Antwort vorgeschlagen Peter Kriegel Samstag, 13. Dezember 2014 11:15
    • Als Antwort markiert deroppi Samstag, 13. Dezember 2014 12:05
    Freitag, 12. Dezember 2014 16:15

Alle Antworten

  • Hallo Michael!

    Bei XML haben wir gute .NET Klassen die einen String (Text) in ein XML Document Object Model (DOM) umwandeln.
    Für HTML gibt es da nix fertig eingebautes vom Microsoft, das mir bekannt ist.
    Dafür musst du dir das HTML Agility Pack von Codeplex herunterladen und in der PowerShell nutzen:

    http://htmlagilitypack.codeplex.com/

    Lee Holmes vom Microsoft PowerShell Team hat darüber einen Artikel geschrieben:

    http://www.leeholmes.com/blog/2010/03/05/html-agility-pack-rocks-your-screen-scraping-world/

    Um aus einem String ein HTML DOM zu machen könnte der Code wie folgt aussehen:

    # In PowerShell 2.0 und früher müssen wir die .NET 2.0 Version der DLL laden
    # Ab der PowerShell 3.0 müssen wir die .NET 4.0 oder 4.5 Version der DLL laden
    If($PSVersionTable.CLRVersion.Major -lt 4) {
      Add-Type -Path 'C:\Pfad\zur\DLL\HtmlAgilityPack.1.4.6\Net20\HtmlAgilityPack.dll'
    } Else {
      Add-Type -Path 'C:\Pfad\zur\DLL\HtmlAgilityPack.1.4.6\Net40\HtmlAgilityPack.dll'
    }
    
    # HTML Text 
    $HtmLText = @'
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Test Dokument</title>
    </head>
    <body>
    <p>Hallo Welt!</p>
    <p><a href="HTTP://www.Microsoft.de">Ich bin Link! </a></p>
    <p><a href="http://www.PowerShell-Group.eu">Noch Linker!</a></p>
    </body>
    </html>
    '@
    
    # Leeres HtmlDocument erstellen
    $HtmlDoc = New-Object HtmlAgilityPack.HtmlDocument
    # Text in das HTML Document laden
    $HtmlDoc.LoadHtml($HtmLText)
    
    # Mit der XPath abfragesprache alle <A> Link Tags suchen und einzeln verarbeiten
    foreach($HtmlLinkNode in $HtmlDoc.DocumentNode.SelectNodes('//a[@href]')) {
        
        # leere Variable für das HReft Attribut
        $Href = ''
    
        # in den Attributen des <A> Tags das HRef Attribut suchen
        ForEach($Attribute in $HtmlLinkNode.Attributes) {
          IF($Attribute.Name -eq 'HRef') {
            # HRef vom <A> Tag auslesen
             $Href = $Attribute.Value
          }
        }
    
        # neues Objekt erstellen, für die gemeinsame Ausgabe vomn Linktext und HRef
        New-Object PSObject -Property @{
          LinkText = $HtmlLinkNode.InnerText
          LinkHRef = $Href
        }


    PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
    auf der deutschsprachigen PowerShell Community

    Mein 21 Teiliger PowerShell Video Grundlehrgang
    Deutsche PowerShell Videos auf Youtube
    Folge mir auf:
    Twitter | Facebook | Google+

    Freitag, 12. Dezember 2014 13:26
  • Vielen Dank Peter!
    Nachdem ich recht viel gesucht und probiert habe, ist mir eine einfachere Lösung gelungen.
    Von dem HtmlAgilityPack hatte ich gelesen, wollte es aber nicht einsetzen.
    So wie unten gezeigt funktioniert es in PS v4 und ist ziemlich mächtig.

    Mein Regex Lösung zur Linksuche muss ich auch noch nutzen, da ja nicht alle Emails als HTML kommen.
    Also suche ich nun zuerst im htmlbody und wenn der leer ist, dann such ich im Text.

    Suche Links und Bilder in einem HTML String:

    $htmlDoc= New-Object -com "HTMLFILE"
    
    
    $page = @'
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Test Dokument</title>
    </head>
    <body>
    <p>Hallo Welt!</p>
    <p><a href="HTTP://www.Microsoft.de">Ich bin Link! </a></p>
    <p><a href="http://www.PowerShell-Group.eu">Noch Linker!</a></p>
    <p><img src="http://www.powershell-group.eu/wp-content/uploads/2013/10/Logo-Gross2.png">
    <p>
    
    <a href="http://google
    
    .de">Ich bin ein kaputter Link, wenn als Text geparsed<
    
    /a
    >
    
    </body>
    </html>
    '@
    
    $htmlDoc.IHTMLDocument2_write($page)
    
    write-host Links
    $htmlDoc.IHTMLDocument2_links | select -expandproperty "href"
    
    write-host Images
    $htmlDoc.IHTMLDocument2_images | select -expandproperty "src"
    
    [void]$htmlDoc.close

    Der Vollständigkeit halber hier noch die Suche im Text mit Filter für bestimmte Endungen.
    Den regex Ausdruck habe ich aus dem Internet, es gibt viele Ansätze, dieser hier lief bei mir am Besten, mit Ausnahme von Links die in mehrere Zeilen aufgebrochen waren.

    # extracting URLs from text
    
    $ExtFilter = "", "txt","jpg", "jpeg","gif","png","bmp","bin", "wmv" ,"dtd"
    
    $text= @'
    Das ist ein Text in dem eine Link enthalten ist.
    Um ganz viel Geld zu bekommen klicken sie hier: https://www.google.de/?gws_rd=ssl#q=ganz+viel+Geld !!!
    Klicken sie sofort und ohne zu denken.
    '@
    
    $regex="(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?"
    $URLs=[regex]::matches($Text, $regex,  [system.Text.RegularExpressions.RegexOptions]::Singleline)     
    Foreach ($URL in $URLs) {
        
        $split=[string]$URL
        $split=$split.split(".")
                       
        if (($ExtFilter -notcontains $split[-1]) -and (@($split).length -gt 1)) {
            write-host $URL
        }    
    }

    Ich bin neu bei PS, also seht mir bitte irgendwelche grauenhaften Konstrukte nach.



    • Bearbeitet deroppi Freitag, 12. Dezember 2014 16:32
    • Als Antwort vorgeschlagen Peter Kriegel Samstag, 13. Dezember 2014 11:15
    • Als Antwort markiert deroppi Samstag, 13. Dezember 2014 12:05
    Freitag, 12. Dezember 2014 16:15
  • Hallo Michael!

    Coole Lösung mit dem COM Object! Danke!

    Man könnte auch den HTML Text auf der Festplatte temporär (im TEMP Verzeichnis) als .htm abspeichernden und in einen unsichtbaren internet Explorer laden. Dieser wird dann auch über COM angesteuert, dann hatt man auch das DOM.


    PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
    auf der deutschsprachigen PowerShell Community

    Mein 21 Teiliger PowerShell Video Grundlehrgang
    Deutsche PowerShell Videos auf Youtube
    Folge mir auf:
    Twitter | Facebook | Google+

    Samstag, 13. Dezember 2014 11:19
  • Hallo Peter,

    die Lösung mit dem IE und der Datei habe ich auch probiert.
    Ist aber fürchterlich langsam und aus irgendeinem Grund ist mir später immer Outlook hängen geblieben. Habe wohl irgendwas mit dem Zugriff auf die Datei übersehen.


    Samstag, 13. Dezember 2014 12:04