3

i'm getting some problem to get a specific row from a powershell body. HR team send email to us, a logic app get the body of email and pass it to a script that disable the user.

The body is like this:

Hi,

the following user have to be dismiss:

#mail: user1@mycompany.com
#mail: user2@mycompany.com
#mail: user2@mycompany.com


Bye
hr team

hrteam@mycompany.com
 

i would like to get only the specific row:

    #mail: user1@mycompany.com
    #mail: user2@mycompany.com
    #mail: user2@mycompany.com

to do this i did a trick with following code:

    $Body
    $SplitBody = $Body.split("").split(" ").Split("#")
    $objetbody = $SplitBody.Replace(" ","").Trim()

and i got following result:

Hi,
the
following
user
have
to
be
dismiss:

mail:
user1@mycompany.com

mail:
user2@mycompany.com

mail:
user2@mycompany.com
Bye
hr
team
hrteam@mycompany.com

after that i pass $objetbody into a foreach and loop all row(at the end of this foreach is put a break becouse it can disable HR mail). The flow work if HR sent only 1 mail to disable.

My question is there is a way to got that specific row that contains the mails?

Thanks

aynber
  • 22,380
  • 8
  • 50
  • 63
Emanuele
  • 193
  • 2
  • 13

2 Answers2

5

Here is a one-liner to output all email addresses using the .NET RegEx class:

[RegEx]::Matches( $body, '(?<=#mail:\s*)\S+' ).Value

The same can be achieved using Select-String:

($body | Select-String '(?<=#mail:\s*)\S+' -AllMatches).Matches.Value

RegEx breakdown:

  • (?<= ... starts a positive look behind pattern, meaning that the sub string we search for must be preceded by the given pattern, but this pattern won't be included in the result
    • #mail:\s* ... literal "#mail:" followed by optional whitespace
  • ) ... ends the look behind pattern
  • \S+ ... any sequence of non-whitespace characters -> the email address

I kept the email address pattern simple, because correctly matching email addresses using RegEx can be hard. Anyway you propably want to do validation as a separate step so you can report invalid addresses. This can be done much simpler using the .NET MailAddress class:

$mailAddresses = [RegEx]::Matches( $body, '(?<=#mail:\s*)\S+' ).Value

foreach( $adr in $mailAddresses) {
    try {
        [System.Net.Mail.MailAddress]::new( $adr )
    } catch {
        # The MailAddress constructor throws FormatException for invalid address
        Write-Error "Invalid mail address: '$adr'"
    }    
}
zett42
  • 25,437
  • 3
  • 35
  • 72
3

You could use a loop in addition to the -match operator and the use of the automatic variable $Matches:

foreach($line in $Body)
{
    if($line -match '^#mail: (.*@.*\.[\w\d]+)')
    {
        $Matches[1]
    }
}

From the example above, $Matches[1] would return the values for the matched capturing group:

user1@mycompany.com
user2@mycompany.com
user2@mycompany.com

If you want to keep #mail: use $Matches[0] instead.

Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • Hi santiago, i tried your code but i got this with $matches[0]: Name Value ---- ----- 0 @mycompany.com $matches[1] is empty i see. Looking forward to hearing from you. Thanks!! – Emanuele Jan 26 '22 at 10:51