[Exchange/PowerShell] Mailadressen toevoegen aan object

Pagina: 1
Acties:

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Exchange 2007 SP1, PowerShell 1.0 en Server 2008.

Ik probeer om een aantal extra adressen toe te voegen aan een Mail-enabled public folder. Mijn CSV-file heeft deze layout:

Folder,Addresses
\TopLevel\NaamOfFolder,"@EmailAddresses=X500:/cn=65F7882E4A403F4B85FE2CD09E43299F0000002FEE1D,X400:C=us,A= ,P=Domain,O=Exchange,S=EPM,,smtp:EPM@domain.nl,SMTP:EPM@domain.com}"

Als ik een adres wil toevoegen met Set-MailPublicFolder dan overschrijft dit de bestaande, daarom gebruik ik deze constructie:

import-csv -path NameOfFile.csv | % {
$temp = Get-MailPublicFolder -Identity $_.Folder
$temp.EmailAddresses.Add($_.Adresses)
Set-MailPublicFolder -Instance $temp
}

Dit lukt niet omdat de inhoud van de variabele (@{EmailAddresses=X500:/cn=65F7882...) natuurlijk geen geldig formaat is voor een mailadres. Daarom heb ik vervolgens geprobeerd om het begin en einde ('@{EmailAddresses=' en '}') weg te halen zodat ik alleen de verschillende adressen gescheiden door een comma in mijn variabele heb zitten. Maar nu wordt die lange string (X500:/cn=65F7882E4A403F4B85FE2CD09E43299F0000002FEE1D,X400:C=us,A= ,P=Domain,O=Exchange,S=EPM,,smtp:EPM@domain.nl,SMTP:EPM@domain.com) gewoon als één entry bijgevoegd.

Als ik het goed heb is deze layout @{Property=Waarde1,Waarde2,Waarde3} een array, maar kan ik hem alleen maar gebruiken als string. Mijn vraag is eigenlijk hoe ik nu de waarden tussen de komma's kan gebruiken in mijn script.

Exchange en Office 365 specialist. Mijn blog.


  • elevator
  • Registratie: December 2001
  • Niet online

elevator

Officieel moto fan :)

Het lastige is dat het op een definitie van een "collection" lijkt, maar het net niet is door de commas, hierdoor kan je ook geen split doen op komma of punt, dus je zal met regular expressions of handmatig parseren aan de slag moeten.

Ik heb even iets in elkaar geprutst wat het ongeveer zou moeten doen:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# $a = "@EmailAddresses=,X500:/cn=65F7882E4A403F4B85FE2CD09E43299F0000002FEE1D,X400:C=us,A= ,P=Domain,O=Exchange,S=EPM,,smtp:EPM@domain.nl,SMTP:EPM@domain.com}"
$a = "@EmailAddresses=,X500:/cn=65F7882E4A403F4B85FE2CD09E43299F0000002FEE1D,X400:O=Exchange,S=EPM,,smtp:EPM@domain.nl}"

Function EmailStrToArray($inp) {
    $addrs = @()
    $counter = 0

    $lastkw = 0

    # now manually parse it.. ugly
    while ($counter -lt $inp.Length) {
        if ($inp[$counter] -eq ":") {
            # new mailtype, find the first preceding comma
            # write-host "asking for position: " $lastkw " => " $counter

            $comma = $inp.SubString(0, $counter).LastIndexOfAny(",")
            if ($comma -le 0) { $comma = 0 }

            # write-host "after fixing, position, lastkw: " $lastkw " => comma: " $comma " => counter:" $counter
            # write-host "New1: " $inp.Substring($comma, ($counter - $comma))
            
            # write-host "New2: " $inp.Substring($lastkw, ($counter - $lastkw - ($counter - $comma)))

            $mailaddr = ($inp.Substring($lastkw, ($counter - $lastkw - ($counter - $comma))))
            if ($mailaddr.Trim().Length -gt 0) {
                $addrs += $mailaddr
            }

            $lastkw = ($comma + 1)
        } # if

        # write-host "Parsing: " $inp[$counter]

        $counter++
    } # while

    return $addrs
}

# first strip of the leading @Emailaddresses
$b = $a.SubString("@EmailAddresses=".Length)
# now to make sure we dont have to fix the parser properly, we mess up the string
$b = ($b.substring(0, $b.length - 1) + ",DUMMY1:DUMMY")
EmailStrToArray $b

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Okay, ontzettend bedankt. Was zelf ook al een beetje tot de conlusie gekomen dat ik moet gaan parsen maar mijn skilz zijn niet l33t genoeg om dat helemaal zelf te bouwen. :)

Ik begrijp wat je doet in de functie, namelijk het opsplitsen van de string in afzonderlijke brokjes. Maar hoe je dat doet kan ik niet volgen, misschien ook omdat ik de write-host regels niet op mijn scherm zie als ik de functie uitvoer. we beginnen dan aan het begin van de string, waar op dat moment @EmailAddresses= al van afgehaald is. Dan moet je dus stoppen na de eerstvolgende komma welke gevolgd wordt door X400:, X500, SMTP: of smtp:. Hoe je dat doet begrijp ik niet. Kun je anders eens uitleggen welke aanpak je gebruikt om uit te vinden waar je start en moet eindigen in de string?

De uitvoer is nu:
code:
1
2
3
4
[PS] D:\Temp>.\testscript.ps1
X500:/cn=65F7882E4A403F4B85FE2CD09E43299F0000002FEE1D
X400:O=Exchange,S=EPM,
smtp:EPM@domain.nl
Het X400 adres mist een stuk, dit zou X400:C=us,A= ,P=Domain,O=Exchange,S=EPM moeten zijn.

Ook zie ik dat we de dubbele komma uit de string moeten halen, dat kan ik met .Replace(",,", ",") oplossen maar zie even niet op welke plek ik die het beste op kan nemen.

Exchange en Office 365 specialist. Mijn blog.


  • elevator
  • Registratie: December 2001
  • Niet online

elevator

Officieel moto fan :)

Alles na een "#" is commentaar in PowerShell, ik heb die Write-Host commandos dus uitgecommentaard, ik had jouw X400 address even aangepast omdat dat makkelijker testen was, als je de originele string (de 1e regel) dus weer actief maakt en de tweede uitcommentarieerd krijgt je het goede resultaat volgens mij.

Wat ik eigenlijk doe is bij elke dubbelepunt gaan kijken naar de eerste beste komma die er voor staat, vervolgens sla ik die positie op. Bij de volgende dubbelepunt pak ik die positie, bereken opnieuw waar de laatste komma staat en pak die string, je hebt dan het resultaat wat je nodig hebt normaal.

Als je dus de volgende string hebt:

code:
1
2
12345678901234567890123456789012345678901234567890
X500:/cn=test,X400:o=Whee,smtp:ohnee


En je bent de tweede dubbelepunt tegengekomen (positie 19), dan zoek je naar de eerste beste komma zoekende vanaf rechts, dat is dan positie 14. Positie 14 (+1, omdat die komma ons niet interesseert) onthouden we in $lastkw.

Vervolgens gaan we net zo lang door tot we de volgende dubbelepunt vinden, positie 31. We zoeken dan wederom de eerst volgende komma op, 26, en dan willen we eigenlijk alles tussen positie 15 en 26 hebben want dan is de string die ons interesseert.

Die string slaan we op in $mailaddr en voegen we toe aan de array :)

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Duidelijk, hier kan ik wat mee. Die "#" had ik helemaal overheen gekeken, dat is logisch natuurlijk. :)

Ik heb het in mijn script ingepast en ben nu op het punt dat ik een array variabele heb met meerdere waardes. Nu moet ik ze per stuk toevoegen aan de bestaande e-mail adressen en dat deed ik eigenlijk zo:
C#:
1
2
3
4
5
import-csv -path NameOfFile.csv | % {
$temp = Get-MailPublicFolder -Identity $_.Folder
$temp.EmailAddresses.Add($_.Adresses)
Set-MailPublicFolder -Instance $temp
}
Maar nu moet ik dus een aantal keer zo'n routine doen, voor iedere waarde in mijn array variabele $adres. Dat probeer ik dan zo:
C#:
1
2
3
4
5
$adres | % {
$temp = Get-MailPublicFolder -Identity $_.Folder
$temp.EmailAddresses.Add(xxxxxxxxxxxxx)
Set-MailPublicFolder -Instance $temp
}
Alleen weet ik niet hoe ik op de plek van xxxxxxxxxxxxx nu aan moet geven dat ik de waarde uit de pijplijn wil gebruiken. Is dat dan $_ of iets dergelijks? Als ik een specifieke Variabele uit de stream wil gebruiken dan kan ik dat met de constructie $_.Naam doen namelijk.

Pff, pittig hoor. :)

Exchange en Office 365 specialist. Mijn blog.


  • elevator
  • Registratie: December 2001
  • Niet online

elevator

Officieel moto fan :)

De $_ lijkt inderdaad altijd de meest lokale variabele te zijn, dit kan je testen door dit te doen:

C#:
1
(1,2,3,4) |% { $_; (5,6,7) |% { $_ } }


en naar de output te kijken - zoals je ziet krijgt de 'inner' $_ precies de waarde die je zou willen en krijgt de buitenste dat ook, dus het reageert zoals je zou willen.

Feitelijk wil je meerdere addressen, aan hetzelfde object toevoegen, ik zou dus zoiets doen (niet getest)!

C#:
1
2
3
4
5
6
7
8
9
10
11
Import-Csv -path NameOfFile.csv |% {
  $pf = Get-MailPublicFolder -Identity $_.Folder

  # Splits de addressen en voeg die allemaal toe
  $Addresses = EmailStrToArray($_.EmailAddresses)
  $Addresses |% { 
          $pf.EmailAddresses.Add($_) 
   }

  Set-MailPublicFolder -Instance $temp
}


Ik weet niet zeker of dat kan, maar dit zou normaal wel moeten lukken. Je kan ook even de signature van een publicfolder.EmailAddresses controleren want misschien kan je gewoon kant en klaar een array toevoegen.

Ik haal expres het "Get-MailPublicFolder" uit de address-foreach omdat dat vermoedelijk een relatief trage actie is en je dan ook de $_ kwijt zou zijn en dus die eerst zou moeten opslaan.

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Mmm, ik heb het nu zo gedaan:
C#:
1
2
3
4
5
6
7
8
9
$adres = EmailStrToArray $b
$pf = Get-MailPublicFolder -Identity $_.Folder

$adres | % {
$AdresToeTeVoegen = $_
If ($AdresToeTeVoegen -like "X400:*") { $AdresToeTeVoegen = $AdresToeTeVoegen.replace(",", ";") }
$pf.EmailAddresses.Add($AdresToeTeVoegen)
Set-MailPublicFolder -Instance $pf
}
Dit werkt prima zo, maar nu wil ik ook nog controleren of een e-mailadres al bestaat. Indien dit het geval is dan wil ik dat hij er verder niets mee doen en verder gaat met het volgende adres uit de array.

Ik slaag er wel in om de check te doen, maar weet niet hoe ik dan zorg dat hij stopt met de loop en door gaat met de volgende:
C#:
1
2
3
4
5
6
7
8
9
10
11
$adres = EmailStrToArray $b
$pf = Get-MailPublicFolder -Identity $_.Folder
$bestaandeAdressen = $pf.EmailAddresses

$adres | % {
$AdresToeTeVoegen = $_
If ($bestaandeAdressen -contains $AdresToeTeVoegen) {$AdresToeTeVoegen = $null} # check of het adres al bestaat en indien ja, dan overslaan
If ($AdresToeTeVoegen -like "X400:*") { $AdresToeTeVoegen = $AdresToeTeVoegen.replace(",", ";") }
$pf.EmailAddresses.Add($AdresToeTeVoegen)
Set-MailPublicFolder -Instance $pf
}
De waarde op $null zetten heeft natuurlijk geen nut. :) Enig idee hoe ik dit kan bereiken? Wat ik wil is dus iets als goto of gosub in BASIC.

Exchange en Office 365 specialist. Mijn blog.


  • elevator
  • Registratie: December 2001
  • Niet online

elevator

Officieel moto fan :)

ipv op $null te zetten, kan je:

C#:
1
2
3
4
# check of het adres al bestaat en indien ja, dan overslaan 
If ($bestaandeAdressen -contains $AdresToeTeVoegen) {
        break
} 


Voor mijn interesse, Is er een reden waarom je het op deze manier doet en niet via het loopje dat ik in mijn vorbeeld gaf, je update nu namelijk de AD database per mailadres ipv per public folder wat het volgens mij een stuk trager maakt :)

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Ah, dat is geen opzet maar gewoon onkunde. :) Mijn hele script is inmiddels al een stukje langer en voor mij redelijk complex. Als het eerst maar werkt dan kan ik het later nog optimaliseren. En eerlijk gezegd zie ik ook niet direct de verschillen, niet op zo'n manier dat ik het gelijk in kan passen en testen.

Break werkt helaas niet, die killt gewoon mijn hele script in plaats van terug te gaan naar de volgende regel in de foreach loop. Ik denk dat ik dit maar even laat zitten, anders moet ik het hele stukje in een if lus gaan bouwen geloof ik.

Exchange en Office 365 specialist. Mijn blog.


  • elevator
  • Registratie: December 2001
  • Niet online

elevator

Officieel moto fan :)

Ah ik zie het ('help about_break') werkt het enkel op de ingebouwde foreach en niet op ForEach-Object (wat |% eigenlijk is), je zal het dan inderdaad in een IF statement moeten bakken, maar ook dat is relatief eenvoudig in jouw voorbeeld, je past gewoon dit aan:

C#:
1
Set-MailPublicFolder -Instance $pf

naar
C#:
1
2
3
if ($AdresToeTeVoegen -ne $NULL) { 
    Set-MailPublicFolder -Instance $pf 
}


Is niet helemaal netjes (je voegt namelijk wel de mailadressen toe), maar je slaat nu de aanroep van 'Set-MailPublicFolder' over dus worden alle wijzigingen welke je op dat object doet feiteiljk weggegooid :)

  • Jazzy
  • Registratie: Juni 2000
  • Nu online

Jazzy

Moderator SSC/PB

Moooooh!

Topicstarter
Netjes of niet, dat is gewoon een prima work-around. :) Bedankt voor het meedenken, het was erg leerzaam.

Exchange en Office 365 specialist. Mijn blog.

Pagina: 1