ConvertFrom-String and locating a specific object.

This topic contains 9 replies, has 3 voices, and was last updated by  Curtis Smith 9 months, 3 weeks ago.

  • Author
    Posts
  • #65061

    Gorstag
    Participant

    Setup: Example info

    $strings = "X-Possible-Header1:Value1X-Possible-Header2:Value2X-Possible-Header3:Value3X-File-Name:MyFileX-File-Size:32X-File-Type:PDFX-File-Date:04:22:78
    "
    $strings = $strings.Replace(":",":`r`n")
    $strings = $strings.Replace("X-","`r`nX-")
    $strings = $strings | ConvertFrom-String
    $strings
    
    

    The possible headers in the example above may or may not be there. So then with the convertfrom-string provides the P# objects the order can change.

    Ask:

    I am trying to figure out how to locate a statically named object and take the value of the next P# object which can be different.

    So for example:
    P8 : X-File-Name:
    P9 : MyFile

    How would I locate X-File-Name regardless of its P# position and take P#+1 as the value I want returned.

  • #65062

    Don Jones
    Keymaster

    I'm not sure that's really the use case for ConvertFrom-String. It's not designed to necessarily make it quicker to locate paired data like you're asking. I think what you'd want is to help it understand that oil name, file size, and file date, are all part of one single object. That might mean parsing the string once for the first set of headers, and then again to get the file info, so that you get a single object with the file name, size, and date as properties. In other words, let _it_ do a bit more of the work, here.

    • #65070

      Gorstag
      Participant

      Thank you for responding.

      Here is the use case. I am attempting to parse out MSG files to pull a specific X-Header. The filtering software that places the X-header always does it exactly the same way but the value is random. Additionally, Exchange sometimes does odd modifications to the value causing it to sometimes be encapsulated in markup like US-ASCII or UTF-8. Also, sometimes it contains return carriages/newlines etc.

      So to try to solve for it I turned the entire header into one long string with no spaces, newlines, or return carriages (Similar to the example above). I then tried to figure out a way to isolate the header and header value. This was done using the example above. T

      This allowed me to isolate the header and the value as objects but since their place is random I cannot figure out how to identify systematically the value I am looking for to a variable for further manipulation.

  • #65073

    Curtis Smith
    Participant

    Why not just use regex to pull the data you want out of your string?

    $strings = "X-Possible-Header1:Value1X-Possible-Header2:Value2X-Possible-Header3:Value3X-File-Name:MyFileX-File-Size:32X-File-Type:PDFX-File-Date:04:22:78" -match "X-Possible-Header3:(.*?)X-"
    $matches[1]
    
    Value3
    • #65074

      Gorstag
      Participant

      SOB, that did it.

      That narrows it down enough that I can clean it up fine.

      Thanks a bunch.

  • #65077

    Curtis Smith
    Participant

    Hey Gorstag,
    The examples provided in the last post seem like 1 Key/Value pair, but the previous posts seem like multiple key/value pairs in a string. So I'm guessing you have something more like the below sample.

    $header = @"
    X-Possible-Header1:
     Value1
    X-Brightmail-Tracker:
     H4sIAAAAAAAAC+NgFvrEKsWRWlGSWpSXmKPExsXiIGUzUZf958IIg5lT9m1jsfjdNY/JgdHj0LwVrAGMUeyZxbrFBYm5CewZs9vbmQo2feWseHTgP3sD48XznF2MXBxCAusZJT6s/c8E4VxilOjo/MncxcjJwSagL/HxyDV2EFtEQE5i+7qNYDazgIREx5vjbCC2sIC6xMTPs8HqWQRUJZ4ef84IYvMKOEh8O/kXyhaUODnzCUsXIwdQb6jEnKPWIGEJAQWJHWdfM0KM15N4tmE3M8R4cYmXR4+ArRICGv/y/Bs2iPpAiTcX1rOCjJEQsJJY9MQfIuwgMfPNb6iwvcSNrTIQYSuJng0dzBC2jsSbibOZYOItnTegyoMket8KQ4SNJHZNmMIOYetLzHp5lRXigAKJ46tb2SYwSs5C8soshFdmITkZwo6WaFk1nRXC1pFYsPsTG4QtL7H97RxmCFtb4syBx0ww9rKFr6HinhJb709lgbAVJaZ0P4SaGSjRsq6TaQEj9ypG4SBnX0/XCCNvQwO9ouTcTL3k/NxNjMCEwMUlx76D8c5b90OMkhxMSqK8sZsWRgjxJeWnVGYkFmfEF5XmpBYfYpTh4FCS4NX7DpQTLEpNT61Iy8wBpiaYNBMH5yFGCQ4eJRFe0R9ANbyg1FOcmQ6RP8Voz9Fz8vJLJo5j70Dkn4tXXzNxtHVdf80kxAJSKSXOux1ktACIk1GaBzcZllRfMYpzMCoJ85qAVPFk5pXAzX4FtJYJaC1rHNjakkSElFQDY6D+j6VXWW6ZHm5kmBO0YHnw8SMH7qRc+j4zwK5k+91EKd4GDf4i7fXFcepLhN1lbiX2nM1179f/+OVZz5z7UefsLaMYso+qnmJb9nBWkNL0jMcrvLm5mlfctt2fXrjEyO4xx48YSTmhPTt1V732mvRxvS5D/oznVZarjq3pEGm1dUvb/NFtvhJLcUaioRZzUXEiAC9AEWGFAwAA
    X-Possible-Header3:
     Value3
    "@
    
    $strings = (-split $header) -join "" -match "X-Brightmail-Tracker:(.*?)X-"
    $matches[1]
    
    H4sIAAAAAAAAC+NgFvrEKsWRWlGSWpSXmKPExsXiIGUzUZf958IIg5lT9m1jsfjdNY/JgdHj0LwVrAGMUeyZxbrFBYm5CewZs9vbmQo2feWseHTgP3sD48XznF2MXBxCAusZJT6s/c8E4VxilOjo/MncxcjJwSagL/HxyDV2EFtEQE5i+7qNYDazgIREx5vjbCC2sIC6xMTPs8HqWQRUJZ4ef84IYvMKOEh8O/kXyhaUODnzCUsXIwdQb6jEnKPWIG
    EJAQWJHWdfM0KM15N4tmE3M8R4cYmXR4+ArRICGv/y/Bs2iPpAiTcX1rOCjJEQsJJY9MQfIuwgMfPNb6iwvcSNrTIQYSuJng0dzBC2jsSbibOZYOItnTegyoMket8KQ4SNJHZNmMIOYetLzHp5lRXigAKJ46tb2SYwSs5C8soshFdmITkZwo6WaFk1nRXC1pFYsPsTG4QtL7H97RxmCFtb4syBx0ww9rKFr6HinhJb709lgbAVJaZ0P4SaGSjRsq6T
    aQEj9ypG4SBnX0/XCCNvQwO9ouTcTL3k/NxNjMCEwMUlx76D8c5b90OMkhxMSqK8sZsWRgjxJeWnVGYkFmfEF5XmpBYfYpTh4FCS4NX7DpQTLEpNT61Iy8wBpiaYNBMH5yFGCQ4eJRFe0R9ANbyg1FOcmQ6RP8Voz9Fz8vJLJo5j70Dkn4tXXzNxtHVdf80kxAJSKSXOux1ktACIk1GaBzcZllRfMYpzMCoJ85qAVPFk5pXAzX4FtJYJaC1rHNjakk
    SElFQDY6D+j6VXWW6ZHm5kmBO0YHnw8SMH7qRc+j4zwK5k+91EKd4GDf4i7fXFcepLhN1lbiX2nM1179f/+OVZz5z7UefsLaMYso+qnmJb9nBWkNL0jMcrvLm5mlfctt2fXrjEyO4xx48YSTmhPTt1V732mvRxvS5D/oznVZarjq3pEGm1dUvb/NFtvhJLcUaioRZzUXEiAC9AEWGFAwAA

    or

    $header = @"
    X-Possible-Header1:
     Value1
    X-Brightmail-Tracker: =?us-ascii?Q?H4sIAAAAAAAAC02SbUhTYRTHee7u7u5Wi+ssdlrL9EYYpab2gmjkLKREQjOC?=
     =?us-ascii?Q?UVjdbLqVrtg07FNqamqZSn1QC5lWFlFhNrMXspi6ULQhlU1xUKmhm1oalL3S?=
     =?us-ascii?Q?vXum9uXyO//zf/7nuQ+HFik6KRWty83WmYxcJkvJSI1qa1Nowp96bfgHZ14r?=
     =?us-ascii?Q?GfW4eYrUoF22ulviZLRfYjCHmk9yWYcl+kp7ofikdUaaO+gsFuUhV4+0DMlo?=
     =?us-ascii?Q?BXMfQf7NQTEuSgg4+3GMwoUTgfXrZ7IMSWmK2QDTHf0SgZcyy2H4noUSWMQA?=
     =?us-ascii?Q?lEy89LI/EwyO6lKvh2TWwLTrkvesnNHAnVkHgdkPumpGeJ3mz+4D+7fjggxM?=
     =?us-ascii?Q?IDzq9SAcHwb91Z8JHK+E8c4OiWAHJgDeN8dh+1qYdLklmIPh++iQSGDEpEFv?=
     =?us-ascii?Q?T7cY60Fgf+4iMIfDNccshVkND+vqfGddErj1eCWO3wgN/UmCrOAjxx0TPvse?=
     =?us-ascii?Q?eNDS5rtBNDSMJGFZA01jRSSWY8HZosZyNFxoKhFhDoGJqivEnF5Y6hRjewqU?=
     =?us-ascii?Q?T/pXotW1/z1I7cKD1P7345gPwOinERHmELA8naEwr4LWyas+fT30vBgm5rix?=
     =?us-ascii?Q?3uPTE2Cm4pwYcxBcPv/Bl7kHivKdpAUtuo38U3bsTojXRiZGhIeZ0rIMYWkn?=
     =?us-ascii?Q?spoRv1syWYDkERqa3GlDy2mCXSZPba7XKpYcOXH0tJ4z6w+ZcjJ1ZhtS0zQL?=
     =?us-ascii?Q?8pmffM/PpMvQ5aYbMvkFnWsTtNSGgF7MLpX//cF75MJCmg0ZuN+NYukLXa/H?=
     =?us-ascii?Q?Cdo+JXx/9731EHRx2TsPoSAFp0op/y1EM0KhzzHOJ89tvxspacT6y8d+8a7F?=
     =?us-ascii?Q?BmP2fLabH0vwY8UHvWOzuYWWKg8xp+oX/YlnpY0NocQPonGgKqBG/Z2aigtj?=
     =?us-ascii?Q?N76KLIjqoCJjH5QMrw1IfdbuTj6oTWz767Ecm4piVHcvcjru22zxE1spx247?=
     =?us-ascii?Q?PJb+aXtScsUZroVKPaB+1npjnXtvQWD3yKbygc1W+/WXBTFvtsTtr1Q2PYwp?=
     =?us-ascii?Q?roIVRuizfmnXukJZ0qznItaJTGbuHxsPujrYAwAA?=
     X-Possible-Header3:
     Value3
    "@
    
    $strings = (-split $header) -join "" -match "X-Brightmail-Tracker:(.*?)X-"
    $matches[1]
    
    =?us-ascii?Q?H4sIAAAAAAAAC02SbUhTYRTHee7u7u5Wi+ssdlrL9EYYpab2gmjkLKREQjOC?==?us-ascii?Q?UVjdbLqVrtg07FNqamqZSn1QC5lWFlFhNrMXspi6ULQhlU1xUKmhm1oalL3S?==?us-ascii?Q?vXum9uXyO//zf/7nuQ+HFik6KRWty83WmYxcJkvJSI1qa1Nowp96bfgHZ14r?==?us-ascii?Q?GfW4eYrUoF22ulviZLRf
    YjCHmk9yWYcl+kp7ofikdUaaO+gsFuUhV4+0DMlo?==?us-ascii?Q?BXMfQf7NQTEuSgg4+3GMwoUTgfXrZ7IMSWmK2QDTHf0SgZcyy2H4noUSWMQA?==?us-ascii?Q?lEy89LI/EwyO6lKvh2TWwLTrkvesnNHAnVkHgdkPumpGeJ3mz+4D+7fjggxM?==?us-ascii?Q?IDzq9SAcHwb91Z8JHK+E8c4OiWAHJgDeN8dh+1qYdLklmIPh++iQS
    GDEpEFv?==?us-ascii?Q?T7cY60Fgf+4iMIfDNccshVkND+vqfGddErj1eCWO3wgN/UmCrOAjxx0TPvse?==?us-ascii?Q?eNDS5rtBNDSMJGFZA01jRSSWY8HZosZyNFxoKhFhDoGJqivEnF5Y6hRjewqU?==?us-ascii?Q?T/pXotW1/z1I7cKD1P7345gPwOinERHmELA8naEwr4LWyas+fT30vBgm5rix?==?us-ascii?Q?3uPTE2Cm4pw
    YcxBcPv/Bl7kHivKdpAUtuo38U3bsTojXRiZGhIeZ0rIMYWkn?==?us-ascii?Q?spoRv1syWYDkERqa3GlDy2mCXSZPba7XKpYcOXH0tJ4z6w+ZcjJ1ZhtS0zQL?==?us-ascii?Q?8pmffM/PpMvQ5aYbMvkFnWsTtNSGgF7MLpX//cF75MJCmg0ZuN+NYukLXa/H?==?us-ascii?Q?Cdo+JXx/9731EHRx2TsPoSAFp0op/y1EM0KhzzHOJ89t
    vxspacT6y8d+8a7F?==?us-ascii?Q?BmP2fLabH0vwY8UHvWOzuYWWKg8xp+oX/YlnpY0NocQPonGgKqBG/Z2aigtj?==?us-ascii?Q?N76KLIjqoCJjH5QMrw1IfdbuTj6oTWz767Ecm4piVHcvcjru22zxE1spx247?==?us-ascii?Q?PJb+aXtScsUZroVKPaB+1npjnXtvQWD3yKbygc1W+/WXBTFvtsTtr1Q2PYwp?==?us-ascii?Q?ro
    IVRuizfmnXukJZ0qznItaJTGbuHxsPujrYAwAA?=
    • #65334

      Gorstag
      Participant

      Hi,

      I've been playing around with this a bit as I have had time. And I came to a realization that I hadn't noticed before. Email headers have a very specific set of rules that govern them (Who would have thought:)

      Each new header has to begin at the start of the line with no whitespace prior. They then have to have a Value: (ValueColon Space ). Additionally, each line of data that has a space or tab (any whitespace really) will be part of that header's data. It will end when the next object repeats the ValueColon Space at the beginning of the line. Finally, the header ends when a new line contains only whitespace.

      So an example:

      X-HeaderOne: My First Value
       My Second Value
      X-headerTwo:
       My first value
       My second value
      X-headerThree: My value
      
      Header ended above ^
      
       

      So what I really need to figure out is how to capture everything between the static header I know and the "next" start. So for example between X-headerTwo: and end at the start of X-headerthree OR on a completely blank line.

      Edit: Looks like i might have the regex dialed in

       (X-Brightmail-Tracker:.*\r?\n(?:^\ +.*\r?\n)*) 
  • #65343

    Curtis Smith
    Participant

    If your pattern as described holds true, you could just convert your headers into a hash table and call the specific header you want from the hash table similar to the below.

    $data = @'
    X-HeaderOne: My First Value
     My Second Value
    X-headerTwo:
     My first value
     My second value
    X-headerThree: My value
    '@ -split "`n"
    
    function parse-headers {
        Param (
            $headers
        )
        $pheaders = @{}
        $headers |
        ForEach-Object {
            If ($_.substring(0,2) -eq "X-") {
                $header = $_.substring(0,$_.indexof(":"))
                $value = ($_.substring($_.indexof(":") + 1)).trim()
            } else {
                $value = ($_.substring($_.indexof(":") + 1)).trim()
            }
            $pheaders[$header] += $value
        }
        $pheaders
    }
    
    $myheaders = parse-headers $data
    
    $myheaders['X-headerTwo']
    My first valueMy second value
    • #65397

      Gorstag
      Participant

      I was able to isolate it using the following method (Because it was something I knew how to do):

      $GetMsgs = Get-ChildItem ./ -Filter '*.msg'
      $GetMsgs = $GetMsgs.fullname
      $reg1 = "(?m)(X-Brightmail-Tracker:.*\r?\n(?:^\ +.*\r?\n)*)"
      
      #Then running the following in a loop
      
      foreach ($GetMsg in $GetMsgs) {
      $ol = New-Object -ComObject Outlook.Application
      $msg = $ol.CreateItemFromTemplate("$GetMsg")
      $headers = $msg.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E")
      
      
      $headers = $headers -replace ":\s",":`r`n "
      
      $headers = $headers | select-string -Pattern $reg1 -AllMatches | % { $_.Matches.Value }
      }
      
      # I then output each result to a txt file for each item in the loop
       

      I am going to poke around with the method you are using because it looks clean and is not something I've done before. Thanks again for the help.

  • #65406

    Curtis Smith
    Participant

    Now that I see exactly what you are doing, you can also do this.

    function parse-headers {
        Param(
            [string]$allheadersstring
        )
        # First we replace all the Carriage Return/Line Feed/Space patterns found with just a space
        # to get all values on the same line.  Then we split the string by the Carriage Return/Line
        # Feed pattern to get all of the individual headers as separate elements in the collection.
        $collectionIndividualHeaders = $allheadersstring -replace "`r`n "," " -split "`r`n"
        $collectionIndividualHeaders | ForEach-Object {
            $IndividualHeader = $_ -split ": "
            [pscustomobject]@{
                header = $IndividualHeader[0];
                value = $IndividualHeader[1]
            }
        }
    }
    
    $getMsgs = ($GetMsgs = Get-ChildItem ./ -Filter '*.msg').FullName
    foreach ($GetMsg in $GetMsgs) {
        $ol = New-Object -ComObject Outlook.Application
        $msg = $ol.CreateItemFromTemplate("$GetMsg")
        $headers = $msg.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E")
        parse-headers $headers | Where-Object {$_.header -eq "X-Brightmail-Tracker"} | Select-Object -ExpandProperty Value
    
    }
    

    The function takes your string of headers as input, and then outputs a Custom PowerShell object for each header/value. You can then use the pipeline to further filter the objects to get the exact header/value you want. Just change your where-object to get a different header.

You must be logged in to reply to this topic.