ROPC – czy polisa 'Block Legacy Authentication’ ma sens?

ROPC, czyli „Resource Owner Password Credentials”- jest częścią OAuth 2.o i daje możliwość logowania aplikacji bezpośrednio podając hasło. zgodnie z opisem na stronie „it’s incompatible with multifactor authentication (MFA)„.

do tego wpisu usiadłem po śledztwie – jak to jest, że niektóre konta logują się bez MFA pomimo, że jest ustawiona polityka Conditional Access zarówno wymuszająca MFA jak i wyłączająca legacy authentication. pomimo to urządzenia nadal mogą logować się do Exchange, bez MFA, korzystając z czystego SMTP…

w EID wygląda to tak:

w tym scenariuszu, to konto reprezentujące skaner, do realizacji scan-to-email – MFD (Multi-Function Device) nadal spokojnie wysyła skany przez EXO. to wzbudziło moją ciekawość – czemu żadna z polityk nie zadziałała, i czemu legacy authentication nadal jest możliwe – a koniec końców: w jaki sposób można omijać CA wyznaczającą politykę bezpieczeństwa? co tak na prawdę blokuje 'block legacy authentication’, skoro nie zablokował tego połączenia?

jak to się dzieje?

odpowiedź na część problemu już jest, ze wspomnianego artykułu:

  • ROPC nie jest zgodne z MFA – mówiąc inaczej, omija je
  • przykładem kiedy jest wykorzystywane – jest użycie ’hasła aplikacji’ dla konta

a co z 'legacy authentication’? jak zwykle chodzi o semantykę i prawidłowe zrozumienie modelu ISO/OSI albo 4/5 warstwowego modelu Internetowego. najpierw ciekawe spojrzenie któreż to protokoły mają status 'legacy’:

  • Autodiscover
  • Exchange ActiveSync
  • Exchange Online PowerShell
  • Exchange Web Services
  • IMAP
  • MAPI over HTTP
  • Offline Address Book
  • Other Clients
  • Outlook Anywhere (RPC over HTTP)
  • POP
  • Reporting Web Services
  • SMTP
  • Universal Outlook

…w zasadzie cały Exchange do niedawna… (czym jest 'Universal Outlook’ wie chyba tylko developer który implementował filtr protokołów w EID), co ciekawe 'legacy’ są tylko protokoły związane z Exchange, co pokazuje równocześnie priorytetowy obszar do zaadresowania elementów bezpieczeństwa. o ile ’łamie się ludzi a nie systemy’, co pokazują statystyki najpopularniejszych metod włamania, to SMTP pozostaje cały czas najłatwiejsze dla bruteforce.  Microsoft

to z czego w końcu korzysta Exchange Online, skoro wszystko jest poblokowane? jak wymienia się z innymi serwerami, skoro nawet SMTP jest na liście?

po pierwsze, trzeba przyjąć do wiadomości, że chodzi o uwierzytelnienie. nie została wyłączona obsługa całego protokołu, również Conditional Access nie pełni roli firewalla – używany jest do weryfikacji uwierzytelnienia (trochę kłamię, bo obsługa sesji to w sumie sporo więcej, ale to advanced feature więc pomijam tutaj). nie chodzi więc np. o SMTP jako protokół wymiany informacji a o SMTP AUTH – i wyłączenie tych starych, jak PLAIN czy LOGIN.

podobnie Outlook – nadal używa jakiejś tam wersji MAPI do komunikacji. problem z ogarnięciem jak zwykle ma naturę semantyczno-marketingową:

  • MAPI jest protokołem aplikacji, językiem jakim rozmawia Outlook z Exchange
  • do tego jest warstwa transportowa – i ta mocno się zmieniła powolnie transformując od paskudnego RPC, przez zamknięcie w HTTP, potem silniejszą integrację z MAPI… na dziś dzień te warstwy nie są już tak oczywiste bo zbyt to jest wymieszane, stąd twory nazewnicze
  • i do tego dochodzi uwierzytelnienie. które jest jakby obok, albo bardziej dosłownie – na froncie. stosuje swoje własne protokoły, które również operują w kilku warstwach, a po zakończonym procesie uwierzytelnienia przekazują pałeczkę do części operującej transportem i aplikacją.

kiedy dokona się analizy i porozkłada się pojedyncze nazwy na ich składowe – zaczyna powoli być jasne które elementy podlegają, a które nie podelagają polityce Conditional Access. CA zajmuje się wyłącznie ostatnim z wymienionych – uwierzytelnieniem i nie dotyka warstw transportu ani aplikacji wykorzystywanych do komunikacji.

kiedy jeszcze używany jest ROPC, poza scenariuszem z EXO? przez developerów/adminów tworzących zapytania przez SPN aplikacji.

w-files

niby szczegół. ale nadal pozostaje wiele niedomówień w kwestii tego kiedy i co de facto zadziała, co ma bezpośrednie przełożenie na bezpieczeństwo. w jaki sposób mechanizmy CA wiedzą żeby nie przetwarzać polityki MFA ale uznać inną?

wszystko jasne z ROPC, tak? ot, przykład z innego tenanta, skonfigurowanego zasadniczo tak samo:

i tutaj ROPC, który wedle dokumentacji nie obsługuje MFA – nagle magicznie zaczyna je obsługiwać i żądać. co więcej – nagle został zaliczony do 'legacy’ – ale jak, skoro ROPC nie jest 'legacy’, bo jest częścią oAuth2?

albo np. Microsoft zaznacza, że basic authentication jest wyłączony. skoro został wyłączony.. to czemu nadal wszędzie jest włączony i po co polisa na coś, co niby od dawna nie powinno działać? pojawiła się polityka 'block legacy authentication’ ale to nie jest wyłącznie. kolejne zdanie, z tego samego artykułu, również idiotyczne:

„We also disabled SMTP AUTH in all tenants where it wasn’t being used.”

nie chce mi się teraz rozkodowywać ruchu i sprawdzać, ale w sumie nie muszę, bo standardy 'starego internetu’ są opisywane w RFC  i SMTP AUTH jest podstawową komendą. skróty myślowe w dokumentacji technicznej prowadzą do zamieszania i dezorientacji. generyczny log pokazujący negocjację protokołu z Outlook (modern auth):

2024-02-19 10:12:45 SMTP AUTH connection started from [192.168.1.100] (client.w-files.pl)
2024-02-19 10:12:46 EHLO client.w-files.pl
2024-02-19 10:12:46 250-server.w-files.pl Hello [192.168.1.100]
2024-02-19 10:12:46 250-AUTH LOGIN PLAIN XOAUTH2 OAUTHBEARER
2024-02-19 10:12:46 250-SIZE 15728640
2024-02-19 10:12:46 250 STARTTLS
2024-02-19 10:12:47 STARTTLS
2024-02-19 10:12:47 220 2.0.0 Ready to start TLS
2024-02-19 10:12:48 TLS negotiation successful (TLSv1.2, ECDHE-RSA-AES256-GCM-SHA384)
2024-02-19 10:12:49 EHLO client.w-files.pl
2024-02-19 10:12:49 250-server.w-files.pl Hello [192.168.1.100]
2024-02-19 10:12:49 250-AUTH LOGIN PLAIN XOAUTH2 OAUTHBEARER
2024-02-19 10:12:50 AUTH XOAUTH2 dXNlcj1hbGljZUBleGFtcGxlLmNvbQFhdXRoPUJlYXJlciB5YTI5LkEwQWY2eHplN…
2024-02-19 10:12:51 235 2.7.0 Authentication successful
2024-02-19 10:12:52 MAIL FROM:<nexor@w-files.pl>
2024-02-19 10:12:52 250 2.1.0 Sender OK
2024-02-19 10:12:53 RCPT TO:<b0b@w-files.pl>
2024-02-19 10:12:53 250 2.1.5 Recipient OK
2024-02-19 10:12:54 DATA 2024-02-19 10:12:54 354 Start mail input; end with <CRLF>.<CRLF>
2024-02-19 10:12:56 Message content sent successfully
2024-02-19 10:12:56 250 2.0.0 OK 2024-02-19 10:12:57 QUIT
2024-02-19 10:12:57 221 2.0.0 server.w-files.pl closing connection

czyli jednym sensownym wyjaśnieniem byłoby 'wyłączyliśmy SMTP AUTH w tenantach gdzie nie ma Exchange’. co za ściema.

nie lubię niejasności. ciężko się zabezpieczać a wśród niejasności rodzą się potencjalne furtki. a po wszystkich tych testach niby wiem więcej a czuję się tak samo bezradny.

eN.

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.