Send As w środowisq hybrydowym

scenariusz

przenosiny do o365 – codzienność. Hybryda Exchange – codzienność. teraz jak zaplanować migrację kont? alfabetycznie? a może lokalizacjami?

największym ogranicznikiem są uprawnienia dla skrzynek. w sfederowanej rzeczywistości nie wszystko jest przechodnie – uprawnienia nadane dla Exchange OnPrem niekoniecznie działają dla userów OnLine i vice-versa. oficjalny guide jest tu: https://technet.microsoft.com/en-us/library/jj200581(v=exchg.150).aspx . dla tego podstawowym wyznacznikiem powinny być skrzynki współdzielone, które powinny być przenoszone grupami -> skrzynka + wszyscy którzy mają do niej dostęp.

co do samego artu – pierwszą rzeczą, na którą warto zwrócić uwagę jest to, że dotyczy on wersji Exchange 2o13 i 2o16. niewprost jest zatem informacja, że Exchange 2o1o jest niewspierany. oficjalnie. ale nieoficjalnie działa tak samo – nie przetestowałem 1oo% przypadqw ale różnic nie widzę.

jest jednak ciekawe zdanie, na którym bym chciał się sqpić:

We don’t, however, support the use of the Send-As, Receive-As, or Send on behalf of mailbox permissions in hybrid deployments between on-premises Exchange and Office 365 organizations

z moich doświadczeń wynika, że jak najbardziej da się nadać SendAs dla dowolnej skrzynki. cały ambaras tkwi w tym, żeby uprawnienie nadać po dobrej stronie – tego DLA kogo są uprawnienia. zaraz pokaże na przykładzie.

jak to zrobić?

z tymi uprawnieniami to jest generalnie trochę namieszane – są aż 3 różne mechanizmy działając na różnych poziomach i do każdego jest inne polecenie. jest jak jest, i stało się tak, że jedna skrzynka jest lokalnie, druga zdalnie. co można zrobić?

środowisko:

  • testuser@w-files.pl jest na Ex 2o1o onprem
  • manager@w-files.pl jest zmigrowany do o365

przykładowe nadanie uprawnień dla skrzynki będzie wyglądało tak:

  • nadanie uprawnień Full Access, bo granularne nie działają. to uprawnienie działa na poziomie folderów w mailboxie.
Add-MailboxPermission -Identity 'testuser@w-files.pl' -User 'manager@w-files.pl' -AccessRights FullAccess
  • nadanie Send on Behalf. to uprawnienie zapisywane jest dla mailboxa.
set-Mailbox -Identity testuser@w-files.pl -GrantSendOnBehalfTo manager@w-files.pl
  • i na koniec uprawnienie Send As. to uprawnienie jest na poziomie obiektu Active Directory ponieważ wiąże się z delegacją uprawnienia. nie do końca rozumiem jak ten mechanizm jest obsługiwany przez Exchange, ale niewątpliwie informacja jest zapisywana dla obiektu AD. i tu jest clue dla działania SendAs dla hybrydy – ponieważ są dwa AD – OnPrem oraz OnLine, to najlepiej wykonać polecenie w obu, a na pewno musi być wykonane w AD, w którym jest obiekt korzystający z niego:
#sendAs in onprem Exchange:
#manager's mailbox is onLine so get-mailbox will not find it. 'name' or 'distinguishedaname' attribute has to be used as Identity
Add-ADPermission -Identity (get-mailbox testuser).name -User "CN=manager,OU=LogicUnion,DC=w-files,DC=pl" -ExtendedRights 'Send As'

#sendAs in OnLine Exchange:
#although testuser's mailbox in onprem, manager will query Azure AD for SendAs permission. below works!
Add-RecipientPermission -Identity testuser@w-files.pl -AccessRights SendAs -Trustee manager@w-files.pl

podsumowanie

no i działa.  a miało nie działać q:

eN.

 

 

Exchange – uprawnienia do kalendarzy zasobów

exchange-logoogólnie

prosty scenariusz: trzeba założyć zasób, reprezentujący samochód firmowy tak, aby ludzie mogli go sobie rezerwować. następnie chcemy aby wszyscy widzieli kto go wypożyczył i dokąd zabrał. standardowo większość informacji jest ukryta i widać tylko ogólny wpis.

w tym celu należy nadać uprawnienia do kalendarza nie jest trudno i jest sporo linków, które szybko wskażą, że można to zrobić poleceniem:

Set-MailboxFolderPermission "roomResource@wfiles.pl:\calendar" -User default -AccessRights reviewer

… ale:

  • po pierwsze to nie zawsze zadziała (w Polsce można uznać, że prawie nigdy)
  • są bardziej złożone scenariusze. no i co daje 'reviewer’?? dla tego warto wiedzieć więcej – np. jakie inne uprawnienia można nadać
  • czemu nadal nie ma wszystkich informacji
  • a co przy jeszcze bardziej wymyślnych wymaganiach dotyczących automatyki? jak jeszcze może 'reagować’ taki obiekt na rezerwację?

lokalizacja

czemu w PL nie zadziała? ponieważ 'calendar’ to nazwa katalogu, a ta jest zlokalizowana. żeby było śmieszniej nazwa będzie zależna od… ustawień przeglądarki w momencie tworzenia obiektu zasobu (użytkownikom definiuje się kraj). sweet. ponieważ mam główną przeglądarkę ustawiona na en-US, żeby nie oglądać raniących w oczy auto-tłumaczeń technetowych czy portalu office365 w którym ciężko się połapać, część obiektów ma 'calendar’ a część 'kalendarz’. zakładając z command line zawsze tworzy 'calendar’ pomimo polskich regionalsów, więc mniemam, że ten sposób jest bardziej deterministyczny (ale trzeba by porobić więcej testów na różnie zlokalizowanych systemach).

czyli zapis ścieżki do konkretnego folderu to „roomResource@wfiles.pl:\kalendarz” . i znów – tyle dość łatwo i szybko można wyszperać na forach… ale pozostaje pytanie – jak wylistować wszystkie katalogi?? skoro jest kalendarz, to pewnie są jakieś inne foldery i może da się z nimi coś zrobić? i jak sprawdzić czy to jest 'calendar’ czy 'kalendarz’? ale najpierw…

uprawnienia

standardowo, po utworzeniu zasobu sali lub ekwipunq jedyne co widać w kalendarzu to 'busy’. equipmentMBXdef

można to zmienić i umożliwić bardziej pełny widok nadając uprawnienia LimitedDetails lub Reviewer (pełna lista uprawnień tutaj). różnica jest dość poważna. ograniczone detale pozwolą na zobaczenie organizatora i lokalizacji ale nie pozwolą otworzyć zdarzenia ze względu na brak uprawnień:

equipmentMBXrevequipementMBXnoaccnadanie uprawnień podglądacza (; pozwoli otworzyć wpis w kalendarzu i w pełni mu się przyjrzeć:

equipmentMBXdetaa gdzie informacje??

na pierwszy rzut oka może wygląda dobrze, ale ktoś choć trochę bardziej spostrzegawczy zauważy, że pole tematu oraz szczegółowe informacje chyba nie dają pełnych informacji. i faktycznie – standardowo, założenie jest takie: ktoś wynajmuje salę, wysyła zaproszenie, więc w tym zaproszeniu umieszcza informacje o czym będzie rozmowa, pewnie agendę, może jakieś materiały dodatkowe itd. zasób sali dostaje to samo zaproszenie co każdy inny – a to byłby niekontrolowany wyciek informacji. nie byłoby miło, gdyby cała firma wiedziała, że właśnie dyrektorzy spotykają się, np. żeby omówić zwolnienia pracowników… dla tego standardowe opcje są ustawione restrykcyjnie i wycinają wszystkie informacje.

są jednak scenariusze, w których niektóre osoby muszą wiedzieć więcej – np. dział logistyki musi wiedzieć gdzie jest samochód i po co. wtedy trzeba wykonać następujące operacje:

  • nadać ludzikom uprawnienia 'limitedDetails’ żeby widzieli 'kto’ ale niewiele więcej (set-MailboxFolderPermission)
  • nadać wybrańcom uprawnienia 'reviewer’ żeby mogli wejść i zobaczyć detale (add-MailboxFolderPermission)
  • no i skonfigurować zasób tak, żeby te informacje przyjmował a nie wycinał. (set-CalendarProcessing)

zobaczmy jakie zachowania można dla zasobu ustawić:

C:\...ive\_scriptz :))o- Get-CalendarProcessing -Identity roomResource@wfiles.pl|fl *


PSComputerName                      : outlook.office365.com
RunspaceId                          : 7518df28-1a3e-49e2-bc1b-6af5eb66bd48
PSShowComputerName                  : False
AutomateProcessing                  : AutoAccept
AllowConflicts                      : False
BookingWindowInDays                 : 180
MaximumDurationInMinutes            : 1440
AllowRecurringMeetings              : True
EnforceSchedulingHorizon            : True
ScheduleOnlyDuringWorkHours         : False
ConflictPercentageAllowed           : 0
MaximumConflictInstances            : 0
ForwardRequestsToDelegates          : True
DeleteAttachments                   : True
DeleteComments                      : False
RemovePrivateProperty               : True
DeleteSubject                       : False
AddOrganizerToSubject               : True
DeleteNonCalendarItems              : True
TentativePendingApproval            : True
EnableResponseDetails               : True
OrganizerInfo                       : True
ResourceDelegates                   : {}
RequestOutOfPolicy                  : {}
AllRequestOutOfPolicy               : False
BookInPolicy                        : {}
AllBookInPolicy                     : True
RequestInPolicy                     : {}
AllRequestInPolicy                  : False
AddAdditionalResponse               : False
AdditionalResponse                  :
RemoveOldMeetingMessages            : True
AddNewRequestsTentatively           : True
ProcessExternalMeetingMessages      : False
RemoveForwardedMeetingNotifications : False
MailboxOwnerId                      : Skoda
Identity                            : Skoda
IsValid                             : True
ObjectState                         : Changed

wszystkich nie ma sensu tłumaczyć, można przeczytać na technecie, nas interesują konkretnie DeleteSubject, DeleteComents. jak widać można również pozwolić na załączniki, kontrolować czy zatwierdzanie jest automatyczne czy wymaga ręcznego potwierdzenia, czy w polu tematu dodawana jest nazwa użytkownika… i inne. przykładowa konfiguracja zasobu:

set-MailboxFolderPermission 'roomResource@wfiles.pl:\kalendarz' -User default -AccessRights limitedDetails
add-MailboxFolderPermission 'roomResource@wfiles.pl:\kalendarz' -User logistics@wfiles.pl -AccessRights reviewer
Set-CalendarProcessing -Identity roomResource@wfiles.pl -DeleteComments $false -DeleteSubject $false

i w takim przypadq dział logistyki może zobaczyć takie krzaczki…

equipmentMBXfulllista folderów

na koniec powrócę do listy folderów. tu niestety niespodzianka: nie da się wylistować folderów dla zasobu. ponieważ zasób jest skrzynką… ale równocześnie nią nie jest. jest – i te foldery są, ale nie jest – bo tak twierdzi system. poniżej mała zabawa – wylistowanie folderów dla regularnego mailboxa, próba wylistowania dla zasobu i dowód, że jednak wszystkie foldery są…

C:\...ive\_scriptz :))o- Get-MailboxFolder -Identity nexor@wfiles.pl -GetChildren

Name                 FolderPath             HasSubfolders
----                 ----------             -------------
Conversation History {Conversation History} False
Dziennik             {Dziennik}             False
Elementy usunięte    {Elementy usunięte}    True
Elementy wysłane     {Elementy wysłane}     False
Kalendarz            {Kalendarz}            True
Kontakty             {Kontakty}             True
Mało istotne         {Mało istotne}         False
Notatki              {Notatki}              False
RSS Feeds            {RSS Feeds}            False
Skrzynka nadawcza    {Skrzynka nadawcza}    False
Skrzynka odbiorcza   {Skrzynka odbiorcza}   True
Sync Issues          {Sync Issues}          True
Wersje robocze       {Wersje robocze}       False
Wiadomości-śmieci    {Wiadomości-śmieci}    False
Zadania              {Zadania}              False


C:\...ive\_scriptz :))o- Get-MailboxFolder -Identity roomResource@wfiles.pl -GetChildren
The specified mailbox "testeq2@netwise.pl" doesn't exist.
    + CategoryInfo          : NotSpecified: (:) [Get-MailboxFolder], ManagementObjectNotFoundException
    + FullyQualifiedErrorId : [Server=VI1PR07MB1375,RequestId=2d356745-d5fe-4ff8-8deb-314d0a8e578b,TimeStamp=2015-11-0
   5 11:40:17] [FailureCategory=Cmdlet-ManagementObjectNotFoundException] 6C1FD1AF,Microsoft.Exchange.Management.Stor
  eTasks.GetMailboxFolder
    + PSComputerName        : outlook.office365.com

C:\...ive\_scriptz :))o- Get-MailboxFolderPermission 'roomResource@wfiles.pl:\inbox'

FolderName           User                 AccessRights
----------           ----                 ------------
Inbox                Default              {None}
Inbox                Anonymous            {None}

przy czym normalny user ma nazwy katalogów po polsq bo zakładając tak miał zdefiniowaną licencję, a zasób po ang. bo był zakładany z linii poleceń, a zasoby licencji nie posiadają. wykorzystanie 'get-mailboxfolderpermission’ w połączeniu z intuicją to jedyny sposób jaki znalazłem, żeby sprawdzić czy dany folder istnieje dla zasobu…

eN.

 

Exchange online: przekierowanie, autoodpowiedź i blokada konta (exit procedure)

scenariusz… niemiły, ale życiowy: pracownik zostaje zwolniony z pracy, mamy skrzynki w Exchange online (wyłącznie) i synchronizację ADSync/ADFS z o365. bloqjemy konto w AD i… nadal odbiera pocztę na urządzeniach mobilnych i outlook. bloqjemy wszystkie funkcje w konfiguracji exchange online (active sync, owa etc)… i nadal może odbierać pocztę (SIC!) – odbierać, kasować etc.

jest tak, ponieważ sesja web dla Active Sync/outlook jest cały czas aktywna i uwierzytelniona. informacja jest scache’owana więc przeźroczyście będzie działać aż nie wygaśnie. dopiero po jakimś czasie wymusi powtórne uwierzytelnienie i przestanie działać. w środowisq on-prem trzeba wywalić sesje z serwerów CAS i pozamiatane. w chmurze takiej możliwości nie ma…

znalazłem jakieś porady polegająca na usunięciu mailboxa, poczekaniu 15 minut i przywróceniu mailboxa… ale w środowisq ADSync tego zrobić się nie da:

The following error occurred during validation in agent ‘Windows LiveId Agent’: ‘Unable to perform the save operation. ‘<UserName>′ is not within a valid server write scope.’ 
Click here for help…

trochę to problematyczne, bo w zasadzie aby mieć pewność, trzeba usunąć userowi licencję, co spowoduje usunięcie mailboxa. uważam, że ze względu na bezpieczeństwo to rozwiązanie pozostawia sporo do życzenia.

i taka ciekawostka dotycząca odpowiedzi automatycznej. skoro pracownik nie będzie już korzystał ze skrzynki, to:

  • chcemy aby maile były przekierowywane do przełożonego
  • nadawca ma odebrać informację zwrotną typu '…proszę kontaktować się z…’

należy wiedzieć, że wyzwalaczem odpowiedzi automatycznej jest zdarzenie 'wiadomość znalazła się w skrzynce’. co oznacza, że jeśli wiadomości są przekierowywane *bez kopii* do skrzynki lokalnej, to autoodpowiedź *nie zadziała*.

eN.

podgląd eventlogu na żywo i reperacja skrzynek exchange

Windows_PowerShell_iconscenariusz

rozjechały się skrzynki na exchange. trzeba posprawdzać bazy oraz zreperować, co się da, z podglądem tego, co się dzieje w danym momencie.

podstawa

do weryfikacji i naprawy mailboxów online służy New-MailboxRepairRequest. problem polega na tym, że to polecenie nie generuje logu tylko wrzuca informacje do eventvwr. ta zmiana jest określana miałem 'alleluja, teraz jest zajebiście’ ale przeglądanie eventvwr, zwłaszcza na żywym systemie nie jest przyjemna – ani nie wiadomo kiedy co się kończy, co zaczyna, zdarzeń jest od groma, żądanie zrobione z linii poleceń, a weryfikacja w taki sposób… no generalnie słabe.

cel

byłoby fajnie móc mieć podgląd life na konsoli tego, jak przebiegają testy. zwłaszcza, jeśli chcemy co jakiś czas zapuścić weryfikację kolejnej 'podejrzanej’ skrzynki.

rozwiązanie

znalazłem w netcie kilka lamerskich skryptów, do podglądu eventvwr na żywo (-> keyword 'tail eventvwr’). czemu lamerskich? ponieważ działają na zasadzie nieskończonej pętli while($true) co już samo w sobie jest bolesne. w tej pętli co 1 sek pobierane jest ostatnie zdarzenie z logu aplikacji. czyli jeśli system jest na prawdę dociążony (a exchange potrafi taki być), może się okazać, że nie zobaczymy tego, na co czekamy. krótko mówiąc – DA SIĘ LEPIEJ (:

rozwiązaniem jest zastawienie pułapki – to nie my pytamy się logu o ostatni event, tylko niech log nam powie, że takowy się pojawił. kwestie wydajności pomijam bo nie badałem – na pewno trzeba pamiętać o wyrejestrowaniu pułapki, żeby nie dociążać systemu. mechanizmem, który to realizuje jest ’register-ObjectEvent’, który rejestruje pułapkę na przechwycenie zdarzenia dla obiektów .NET.

oczywiście nie każde polecenie zdarzenia generuje /: aby to sprawdzić, wystarczy zwykły get-member. sprawdźmy dla get-eventlog:

[PS] C:\Windows\system32>Get-EventLog -LogName application -Newest 1 |gm


   TypeName: System.Diagnostics.EventLogEntry#application/MSExchange ADAccess/1074006048

Name                      MemberType     Definition
----                      ----------     ----------
Disposed                  Event          System.EventHandler Disposed(System.Object, System.EventArgs)
CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedTyp
Dispose                   Method         System.Void Dispose()
Equals                    Method         bool Equals(System.Diagnostics.EventLogEntry otherEntry), boo
GetHashCode               Method         int GetHashCode()
GetLifetimeService        Method         System.Object GetLifetimeService()
GetType                   Method         type GetType()
InitializeLifetimeService Method         System.Object InitializeLifetimeService()
ToString                  Method         string ToString()
Category                  Property       System.String Category {get;}
CategoryNumber            Property       System.Int16 CategoryNumber {get;}
Container                 Property       System.ComponentModel.IContainer Container {get;}
Data                      Property       System.Byte[] Data {get;}
EntryType                 Property       System.Diagnostics.EventLogEntryType EntryType {get;}
Index                     Property       System.Int32 Index {get;}
InstanceId                Property       System.Int64 InstanceId {get;}
MachineName               Property       System.String MachineName {get;}
Message                   Property       System.String Message {get;}
ReplacementStrings        Property       System.String[] ReplacementStrings {get;}
Site                      Property       System.ComponentModel.ISite Site {get;set;}
Source                    Property       System.String Source {get;}
TimeGenerated             Property       System.DateTime TimeGenerated {get;}
TimeWritten               Property       System.DateTime TimeWritten {get;}
UserName                  Property       System.String UserName {get;}
EventID                   ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}

no i słabo – niby jest 'disposed’ ale to nic nie daje. a to dla tego, że obiektem, który jest zwrócony, jest konkretny 'event’. jest jednak wywołanie polecenia, które 'podłącza się’ do eventlogu a nie do jego zawartości:

[PS] C:\Windows\system32>get-eventlog -List|gm


   TypeName: System.Diagnostics.EventLog

Name                      MemberType Definition
----                      ---------- ----------
Disposed                  Event      System.EventHandler Disposed(System.Object, System.EventArgs)
EntryWritten              Event      System.Diagnostics.EntryWrittenEventHandler EntryWritten(System.Object, System....
BeginInit                 Method     System.Void BeginInit()
Clear                     Method     System.Void Clear()
Close                     Method     System.Void Close()
CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose                   Method     System.Void Dispose()
EndInit                   Method     System.Void EndInit()
Equals                    Method     bool Equals(System.Object obj)
GetHashCode               Method     int GetHashCode()
GetLifetimeService        Method     System.Object GetLifetimeService()
GetType                   Method     type GetType()
InitializeLifetimeService Method     System.Object InitializeLifetimeService()
ModifyOverflowPolicy      Method     System.Void ModifyOverflowPolicy(System.Diagnostics.OverflowAction action, int ...
RegisterDisplayName       Method     System.Void RegisterDisplayName(string resourceFile, long resourceId)
ToString                  Method     string ToString()
WriteEntry                Method     System.Void WriteEntry(string message), System.Void WriteEntry(string message, ...
WriteEvent                Method     System.Void WriteEvent(System.Diagnostics.EventInstance instance, Params System...
Container                 Property   System.ComponentModel.IContainer Container {get;}
EnableRaisingEvents       Property   System.Boolean EnableRaisingEvents {get;set;}
Entries                   Property   System.Diagnostics.EventLogEntryCollection Entries {get;}
Log                       Property   System.String Log {get;set;}
LogDisplayName            Property   System.String LogDisplayName {get;}
MachineName               Property   System.String MachineName {get;set;}
MaximumKilobytes          Property   System.Int64 MaximumKilobytes {get;set;}
MinimumRetentionDays      Property   System.Int32 MinimumRetentionDays {get;}
OverflowAction            Property   System.Diagnostics.OverflowAction OverflowAction {get;}
Site                      Property   System.ComponentModel.ISite Site {get;set;}
Source                    Property   System.String Source {get;set;}
SynchronizingObject       Property   System.ComponentModel.ISynchronizeInvoke SynchronizingObject {get;set;}

bingo! tu pojawia się 'entryWritten’! a więc zarejestrujmy pułapkę, przefiltrujmy zdarzenia, które nas interesują – i jeśli takowe się pojawi, wyświetlmy na ekran. opis eventów, jakie generuje new-mailboxrepairrequset można znaleźć na technecie. poniżej draft skryptu, który można sobie dowolnie rozbudować. dla czytelności zapisany w kilq linijkach.

$evtlog=Get-EventLog -list|?{$_.log -eq 'application'}

Register-ObjectEvent -InputObject $evtlog -EventName EntryWritten -SourceIdentifier EventTrap -Action{
  $id=$event.SourceEventArgs.Entry.EventID;
  if($id -gt 10041 -and $id -lt 10062) {
    write-host "$id -> $($event.SourceEventArgs.Entry.Message)"
  }
}

na początq podłączamy się do konkretnego logu – logu aplikacji. następnie dla tego logu rejestrujemy pułapkę na pojawienie się nowych zdarzeń i definiujemy akcję. ponieważ na poziomie rejestracji nie ma możliwości zdefiniowania żadnych filtrów, wszystko trzeba zdefiniować wewnątrz ciała skryptu. po dokonaniu rejestracji, w konsoli będą się pokazywać wszystkie logi pomiędzy 10041-10062. oczywiście warto je ładniej wyświetlić i zrobić pełną obsługę… aby tego dokonać, kluczowym jest obiekt $event.SourceEventArgs.Entry, który jest de facto eventem pojawiającym się w logu, czyli można dostać się do wszystkich parametrów takich jak przy ’ Get-EventLog -LogName application -Newest 1 |gm’.

na koniec trzeba pamiętać o wyrejestrowaniu!! na skróty, wyrejestrowanie wszystkich:

get-event|unregister-event

eN.

 

 

 

jak sprawdzić podstawowy adresy SMTP

adresy email zapisane są w atrybucie wielowartościowym proxyaddresses. adres podstawowy wyróżniony jest dużymi literami SMTP. zatem trick polega na wylistowaniu wszystkich tych wartości z tablicy, które są dużymi literami. służy do tego operator cmatch. w poniższym przykładzie dla o365:

get-msoluser -all|select userprincipalname,@{N="primarySMTP";E={$_.proxyaddresses -cmatch 'SMTP'}}

eN.

550 5.4.1 recipient@domain.com: Recipient address rejected: (Access Denied)

taka ciekawostka: exchange online. założony nowy user… tfu! odblokowany stary user. standard nazewniczy loginów jest jakiś-tam więc każdemu userowi dodaje się imie.nazwisko@domena.com . wszystkim działa.. temu nie. serwer zwraca błąd 5.4.1 acc denied. czytam sobie linki z opisami – wszyscy sugerują zmianę typu domeny na Internal Relay czyli „domenę przekazywania wewnętrznego” [te polskie nazwy. ciągle nie mogę się połapać w tym panelu. PowerShell RZĄDZI! (: ].

co to oznacza? to oznacza, że trzebaby uznać, że adresy wewnętrzne są… adresami zewnętrznymi. no może i zaczęłoby działać, ale nie akceptuję takiej bzdury.

po wielu testach i 2o minutach później działa. rozwiązanie:

sprawdzam jakie są adresy zdefiniowane, zmieniam alias z głównym, a potem z powrotem.

get-mailbox uname|select emailaddr*

EmailAddresses                                                                                EmailAddressPolicyEnabled
--------------                                                                                -------------------------
{SMTP:user.name@domain.com, smtp:uname@domain.com}                                                            False

set-mailbox uname -emailaddresses SMTP:uname@domain.com,user.name@domain.com
set-mailbox uname -emailaddresses SMTP:user.name@domain.com,uname@domain.com

…i działa. niby to samo a jednak nie to samo. cytując filmografię „noone’s perfect” ewentualnie „sowy nie są tym, czym się wydają”.

eN.

 

Exchange 2o1o, PS2.o – personal quota limits

PS2.o nie ułatwia życia… no ale czasem trafia się na takie środowisko i trzeba. szybka wrzuta, bez specjalnego tłumaczenia: sprawdzić kto ma włączone własne limity skrzynkowe oraz jaka jest obecnie zajętość skrzynki, żeby wiedzieć o ile można od razu przyciąć.

w tym celu trzeba połączyć wyniki get-mailbox i get-mailboxstatistics:

get-personalQuotaLimits.ps1

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
$personalLimits=Get-Mailbox |?{$_.UseDatabaseQuotaDefaults -eq $false}

foreach($pl in $personalLimits){
    $mbx=get-mailboxstatistics $pl
    add-member -inputObject $pl -MemberType NoteProperty –Name totalItemSize –Value $mbx.totalitemsize.value.toMB()
    add-member -inputObject $pl -MemberType NoteProperty –Name deleteItemSize –Value $mbx.totaldeleteditemsize.value.toMB()
    add-member -inputObject $pl -MemberType NoteProperty –Name databasename –Value $mbx.databasename
    add-member -inputObject $pl -MemberType NoteProperty –Name lastlogontime –Value $mbx.lastlogontime
}
$personalLimits|select name,`
    @{n='warning';e={$_.IssueWarningQuota.value.toMB()}},`
    @{n='sendQuota';e={$_.ProhibitSendQuota.value.toMB()}},`
    @{n='Receive Quota';e={$_.ProhibitSendReceiveQuota.value.toMB()}},`
    totalitemsize,deleteItemSize,databasename,lastlogontime|`
        Export-csv -NoTypeInformation -Delimiter ';' C:\temp\personalLimits.csv -encoding UTF8

ciekawostka: commandlety Ex2o1o są dostarczane jako snapin a nie moduł… ot taki archaizm.

eN.

Exchange online, powershell, kontakty i rezerwacja sal

to, co jest piękne w PS to fakt, że kiedy się go pozna, wszystko jedno do jakiego produktu się usiądzie – chwila moment i można szybko wyciągać statystyki, tworzyć obiekty, zestawienia i co kolwiek potrzeba. z jednego miejsca i bez różnych GUI.   <3 <3 ^^

przesiadka z Exchange onPremise na Exchange onLine jest bezbolesna – ot trochę mniej poleceń. wymagania? żadne. wystraczy po prostu zestawić sesję z serwerem i zaimportować sesję i stacja zmienia się w konsolę zarządzającą Exchange. po imporcie sesji dostępny jest moduł, którego nazwa jest generowana jakimś pseudolosowym algorytmem. dostępne polecenia można wylistować przy pomocy get-command:

C:\...ive\_scriptz :))o- Import-PSSession $session
WARNING: The names of some imported commands from the module 'tmp_50wtbfhh.kkk' include unapproved verbs that might
make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the
Verbose parameter. For a list of approved verbs, type Get-Verb.

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0        tmp_50wtbfhh.kkk                    {Add-AvailabilityAddressSpace, Add-DistributionGroupMember...


C:\...ive\_scriptz :))o- get-command -Module tmp_50wtbfhh.kkk

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Function        Add-AvailabilityAddressSpace                       tmp_50wtbfhh.kkk
Function        Add-DistributionGroupMember                        tmp_50wtbfhh.kkk
Function        Add-MailboxFolderPermission                        tmp_50wtbfhh.kkk
Function        Add-MailboxPermission                              tmp_50wtbfhh.kkk
Function        Add-ManagementRoleEntry                            tmp_50wtbfhh.kkk

[...]

do założenia kontaktu [bo przecież nie będę wyklikiwał z interfejsu, fuj] jest polecenie 'new-mailContact’. okazuje się jednak, że ma ono bardzo ograniczoną listę parametrów, nie pozwalając ustalić takich szczegółów jak organizacja, stanowisko, telefon etc. i tu znów piękno PS – polecenie to nie tylko tworzy obiekt typu 'mailContact’ ale również go zwraca. przypomnę, że PS zwraca obiekty przez referencję dzięki czemu wszystko można 'pajpować’. ponieważ jest drugie polecenie – 'set-contact’, które przyjmuje wszystkie wymagane parametry a jako wskazanie może użyć zarówno ID jak bezpośredniej referencji do obiektu 'mailContact’, można utworzyć prostego jednolinijkowca, który zrobi co trzeba:

New-MailContact -ExternalEmailAddress user.name@company.org -Alias user.name -Name "User Name" -FirstName User -LastName Name |Set-Contact -Company CompanyOrg -MobilePhone "23-666-232323" -department "w-files"

czyli gdyby chcieć ten prosty znaczek '|’ zapisać na polski byłoby to mniej-więcej – 'a następnie przekarz go przez referencję do następnego polecenia’

i jeszcze „jedna rzecza” która się przydaje – rezerwowanie sal przez osoby z zewnątrz. standardowo takiej możliwości nie ma. w ex2k13 uzyskuje się to poprzez 'calendar processing’:

#wylistuj zasoby sal
get-mailbox -RecipientTypeDetails RoomMailbox

#sprawdź parametr akceptacji przez kontakty zewnętrzne:
(get-calendarProcessing <roomID>).ProcessExternalMeetingMessages

set-calendarProcessing <roomID> -ProcessExternalMeetingMessages $true

to jeszcze nie wystarczy. jeszcze jedno wymaganie i jeden 'trick’:

  • adres dokonujący rezerwacji musi istnieć jako kontakt na serwerze [poprzedni przykład]
  • a trick polega na tym, że nie zadziała dodanie w spotkaniu pokoju tak, jak to się zwyczajowo robi na homeserwerze. należy adres wpisać tak, jak zaprasza się zwykłą osobę.

eN.

 

 

 

 

jak sprawdzić build Exchange … ten prawdziwy

po instalacji UR i sprawdzeniu wersji [build number], exchange cały czas pokazuje świeżutką wersję bez builda. wersję można sprawdzić w konsoli lub z PS:

(Get-ExchangeServer <exchangeServerName> ).admindisplayversion

okazuje się, że kwestia wersji nie jest taka trywialna, kiedy przyjrzeć się jej bliżej. kilka zebranych informacji:

  • różne komponenty mają różne wersje.to co się zazwyczaj sprawdza, to wersja 'core’ czyli głównego silnika.
  • wersje zapisywane są w różnych miejscach. ta pokazywana w konsoli oraz powyższy skrypt, zaczytuje je z obiektu w AD z partycji konfiguracji. dla Ex2kd to jest:
CN=<ExchangeServerName>,cn=servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),cn=administrative groups,cn=<OrganizationName>,cn=Microsoft Exchange,cn=Services,cn=configuration,DC=<domain>,DC=<name>

ufff… oczywiście można tą ścieżkę wyciągnąć poleceniem:

(Get-ExchangeServer <ExchangeServerName>).distinguishedname

wersja zapisana jest w atrybucie 'serialNumber’ więc odczytać ją można:

([ADSI]"LDAP://$((Get-ExchangeServer <ExchangeServerName>).distinguishedName)").SerialNumber

parametr nie jest uaktualniany przy  instalacji UR – stąd rozjazd.

  • wersję można również sprawdzić w kluczu rejestru „HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v<versionNumber>\<roleName>” – są tam klucze o nazwach 'configuredVersion’ i 'unpackedVersion’. te również nie są poprawiane.

sprawdzić prawdziwą wersję można na dwa sposoby:

  • z GUI – w EMC [górne menu]-> help -> about

exchangeversion

  • albo sprawdzając wersję pliq ExSetup z katalogu bin:
 (Get-Command 'C:\Program Files\Microsoft\Exchange Server\V14\Bin\ExSetup.exe').FileVersionInfo|fl *

eN.