Sunday, July 16, 2017

Exchange 2010 SP3 - Search-AdminAuditLog (1)

After my previous blog posts on Exchange 2016 (in French), this post marks both a return to English (probably brief) and a return to Exchange 2010. I still manage Exchange 2010 servers and recently needed to examine the auditing of changes to mailbox permissions made by administrators (a subject that I've covered in the past as well). The context? Troubleshooting a third-party auditing tool that uses the PowerShell cmdlet Search-AdminAuditLog. Pending a solution to the problem in question, I wanted to see to what extent the same results could be achieved with native Exchange tools.


First, I'll present the scenario.

The mission is to create a report that will list changes made to mailbox permissions with the Add-MailboxPermission cmdlet (and optionally the Remove-MailboxPermission cmdlet). We should remember that even if we make changes in the Exchange Management Console (EMC), or Exchange Admin Center (EAC) in later versions of Exchange, these interfaces use PowerShell cmdlets behind the scenes to execute the desired action. I will also point out that by default administrators are denied access to user mailboxes - unless they execute the Add-MailboxPermission cmdlet that we will audit. Once created, the report should be sent to a designated auditor.

Next, I will execute the command and observe how Exchange records the action in the Event Viewer logs.

For example, the administrator "xadmin" grants himself Full Access to the mailbox of Alex Heyne:

Note: yes, you can click on the image to enlarge it.

Such an action is recorded in the MSExchange Management log of the Event Viewer :

Almost all actions performed by administrators are recorded in this log so we might have to use the "Find" tool to locate the actions that interest us, for example:

The action is only recorded on the server where it was executed (EX13-2 in this case). If we search for the action on EX13-1, there will be no result:

However, our objective is to discover any use of the Add-MailboxPermission cmdlet rather than locating single examples of the event in the MSExchange Management log. For this, we need to use another cmdlet: Search-AdminAuditLog.

I can execute the command with the expected results on EX13-2:

I also notice that the Search-AdminAuditLog cmdlet apparently examines the logs of other servers, since I obtain the same results on EX13-1 (note that the "OriginatingServer is still EX13-2):

We still do not have our report but we are on the right track. Indeed, the reporting function of the third-party software does use the Search-AdminAuditLog to retrieve the actions to be audited.


We are on the right track but I already notice something missing in the results of the Search-AdminAuditLog cmdlet. We see ...

  • Object modified (Alex.Heyne)
  • CmdletName (Add-MailboxPermission)
  • Caller (XADMIN)

So XADMIN executed the command Add-MailboxPermission against the mailbox of Alex.Heyne.

But what permissions were granted and to whom? Himself? Someone else?

We should keep in mind that the entry in the Event Viewer (shown in one of the screenshots above) does indicate these details.

After some research, I discovered that the information we want is present but not displayed but default. We are supposed to observe the property "CmdletParameters" with (in braces) "Identity", "User" and "Access rights" and realize this is a hash-table containing "name-value" pairs. We need to extract these using an array.

I used this article as a reference but was not able to obtain the same results:

Next, I attempted to expand the CmdletParameters property (successfully) but the output was not what I would have liked. I will not present all the variations attempted but in the end, this was the most readable:

So, for a single action (XADMIN grants himself Full Access to the mailbox of Alex Heyne), we have three separate entries. The auditor would have to be able to see the relationship between the three items that (by default) are not united in a single entity (unlike the presentation in the Event Viewer, once again).

While I could not create an array as described in the article cited earlier...

Parsing the Admin Audit Logs with PowerShell

It did include a script by Matthew Byrd that is supposed to format the output of the Search-AdminAuditLog so it is easier to interpret. I thought I would give this a try.


First, we download the script from the TechNet Gallery (Script Center):

Get-SimpleAuditLogReport script

Second, we declare a variable and assign it the output of the Search-AdminAuditLog as shown in the screenshot below.

Third, we pipeline the result to the Get-SimpleAdminAuditLog.ps1 script:

Note: click to enlarge.

This is much better! In the FullCommand field, we see the exact command that was executed. The auditor still needs to understand what that command accomplishes but no longer has to determine the relationship between three separate items as before.

But can we export the content to a file?

Yes we can:

And can we send the file to the auditor? Yes! In my case, I had to create a script for this (simple text to be saved and then executed as a .ps1 file):

The operation is successful and the auditor (we'll pretend user Alan Reid holds this role) does indeed receive the .csv attachment:

However, some may consider that the presentation is not the best:


I thought that HTML might allow for a more attractive and perhaps even readable presentation.

First, this is what I tried:

You might want to ignore what is inside the orange frame. Without further formatting, the output is really no better than our .csv file. With the -head parameter (please observe the details in the screenshot above), we can create a document like this:

We can combine all the elements so the file is sent to the auditor:

Note: we can also configure the Task Scheduler to run the script at the interval of our choice.


With some instruction, our auditor should be able to make sense of the HTML file. We can add other events as desired after the -Cmdlets section of the script. All in all, it seems like an acceptable solution if we do not have a third-party tool (or if our third-party tool stops functioning after an insufficiently tested update...).

And giving credit where credit is due...

Besides the text already cited twice above, I also used the following resources to construct my script(s):

Windows PowerShell Tip of the Week - ConvertTo-Html

Trying to pipe Export-Csv to Send-MailMessage

Saturday, July 8, 2017

Exchange 2016 (25) : le mode maintenance pour le DAG (2)

English summary: in my previous blog post, I outlined the procedure to place our Exchange DAG in maintenance mode. The post became rather lengthy because I not only presented the steps to follow but also verified the effect of the commands and resolved differences between the sources that I consulted. I opted to save the presentation on taking the DAG out of maintenance mode for a later blog post (here). In fact, this presentation proved to be quite short and I realize I could have just added to the previous blog post without increasing its length that much more. Finally, I decided to post the procedure here, in the few paragraphs below.


Dans mon texte précédent, j'ai examiné la marche à suivre pour mettre notre DAG (Database Availability Group) en mode maintenance  selon la nouvelle méthode pour les versions d'Exchange 2013 et 2016. Le texte s'est allongé parce que j'ai non seulement présenté la marche à suivre mais vérifié l'effet des commandes (et résolu des différences entre les sources que j'ai consultées pour la rédaction du texte). J'ai donc remis à plus tard (à ce texte) la marche à suivre pour sortir le DAG du mode maintenance.

Note : est-ce un abus du langage de dire "mettre le DAG en mode maintenance" ou l'en "sortir" ? Je me pose la question dans la mesure où ce n'est pas le DAG entier qui passe en mode maintenance mais seulement un des serveurs qui en est membre à la fois.

Je vois aussi qu'on se sert des termes "mise hors ligne" et "remise en ligne" du DAG (en fait, du serveur membre en question, comme nous venons de le préciser). Quand j'ai remis notre DAG en ligne, grâce à une demi-dizaine de commandes PowerShell, je me suis rendu compte qu'avec un peu de persistance j'aurai pu attacher la description de cette procédure à la fin du texte précédent, sans vraiment l'allonger davantage. Mais ce qui est fait est fait. La remise en ligne du DAG fera l'objet de ce texte, beaucoup plus court que le premier.

Pour sortir le DAG du mode maintenance, il s'agit d'exécuter les commandes suivantes (dans l'ordre), gardant à l'esprit que c'est le serveur EX16-4 que nous avons mis en mode maintenance :

Set-ServerComponentState EX16-4 -Component ServerWideOffline -State Active -Requester Maintenance

Resume-ClusterNode EX16-4

Set-MailboxServer EX16-4 -DatabaseCopyActivationDisabledAndMoveNow $False

Set-MailboxServer EX16-4 -DatabaseCopyAutoActivationPolicy Unrestricted

Set-ServerComponentState EX16-4 -Component HubTransport -State Active -Requester Maintenance

Voici à quoi cela ressemble :

Et c'est tout.

Bien entendu, nous ferions bien de vérifier l'état du DAG, de la réplication et des bases de données avec les mêmes commandes que nous avons utilisées dans le texte précédent, soit :

Get-DatabaseAvailabilityGroup DAG1 -status | format-list

Get-MailboxDatabase | Get-MailboxDatabaseCopyStatus


Monday, June 26, 2017

Exchange 2016 (24) : le mode maintenance pour le DAG (1)

English summary: with Exchange 2010, we could place Database Availability Group (DAG) servers in maintenance mode with a simple script. Since Exchange 2013, this is supposedly no longer possible or at least recommended. After consulting various sources (cited at the end of the text), I demonstrate the method that worked for me. It is essentially a matter of executing a number of PowerShell cmdlets that modify not only the status of the DAG but also Client Access and Transport functions.


La mise en mode maintenance pour les DAG (Database Availability Groups) ne fonctionne plus de la même manière pour Exchange 2016 (ou 2013) que pour Exchange 2010.

Avec Exchange 2010, il s'agissait d'exécuter le script ci-dessous pour la mise hors ligne du serveur auquel on allait appliquer des mises à jour de sécurité (ou autres) :


Après l'installation des mises à jour (et le redémarrage du serveur), il suffisait d'exécuter le script ci-dessous pour remettre le DAG en ligne :


Il convient de préciser que si le serveur tenait des copies dites "actives" des bases de données, ou bien le rôle "PAM" (Primary Active Manager) avant la mise hors ligne, l'exécution du second script ne rétablissait pas le statu quo antérieur. Il fallait déplacer les ressources qu'on voulait remettre au serveur en question par une opération distincte.

De plus, le script n'agissait que sur le fonctionnement du DAG. Les autres rôles (accès client et transport) ne subissaient aucun effet.

Avec Exchange 2016, ces scripts sont toujours disponibles mais il paraît que nous ne devons pas les utiliser (si j'ai bien compris les discussions à ce sujet sur divers forums en ligne dont les forums Exchange de TechNet).

Il faut plutôt suivre le processus que je vais présenter dans les lignes suivantes.


Voici le statu quo à notre point de départ. Nous allons mettre en mode maintenance le serveur EX16-4 qui tient la copie active de la base de données MBXDB-01 ainsi que le rôle "PAM" de notre DAG :

1. Purger les files d'attente

Nous commençons le processus par l'exécution de cette commande :

Set-ServerComponentState EX16-4 -Component HubTransport -State Draining -Requester Maintenance

Dans mon réseau d'essai, les files d'attente sont déjà vides. Les voici avant l'exécution de la commande :

C'est à peu près pareil sur EX16-3 :

De plus, je n'observe aucun changement après l'exécution de la commande.

2. Faire redémarrer deux services Transport

En fait, il est recommandé de faire redémarrer deux services Transport afin que le changement prenne effet tout de suite...

Restart-Service MSExchangeTransport

Restart-Service MSExchangeFrontEndTransport

Note : certaines sources que j'ai consultées ne mentionnent que le premier service.

Note : je me trouve au serveur EX16-3 mais je veux que ces commandes agissent sur le serveur EX16-4. Entre autres options, je peux recourir à "Invoke-Command" :

Mais quel effet ces commandes ont-elles ?

D'une part, des messages s'accumulent dans la file d'attente "ShadowRedundancy" du serveur EX16-4 (ce sont des messages de la boîte "Health Mailbox [GUID]")

D'autre part, le serveur EX16-3, lui, perd sa file d'attente "ShadowRedundancy" :

Note : il faudra que je me renseigne sur le rôle de ces messages qui s'accumulent dans la file d'attente du serveur EX16-4. Je pose comme hypothèse qu'ils doivent avoir une fonction de "message de vie" pour vérifier la voie de communication entre les deux serveurs.

3. Rediriger des messages en attente de livraison vers d'autres serveurs

Il s'agit d'exécuter cette commande :

Redirect-Message -Server EX16-4 -Target

Note : il faut, paraît-il, utiliser le FQDN du serveur cible.

4. Déplacer le rôle "PAM" vers un autre membre du DAG

Nous utilisons deux sortes de commandes PowerShell pour gérer le cluster (le DAG se bâtit sur la fondation du service cluster de Windows) :


Pour observer le statu quo, nous utilisons...


Je constate que le serveur EX16-4 est le propriétaire du nœud pour le groupe du cluster "Groupe du Cluster".

Note : c'est pareil dans la version originale anglaise : le "Cluster Group" a pour nom "Cluster Group". 

Je fais du serveur EX16-3 le propriétaire du nœud avec la commande suivante (et il faut bien utiliser le nom français) :

Move-ClusterGroup "Groupe du cluster" -Node EX16-3

Et cela revient à transférer le rôle PAM vers EX16-3... mais sans mettre EX16-4 hors ligne.

Observez que l'état du nœud est toujours "Up") :

Ainsi, nous devons également suspendre EX16-4 afin qu'on ne puisse pas lui renvoyer le rôle PAM en plein entretien par mégarde : 

Suspend-ClusterNode EX16-4

Note : cela n'a aucun autre effet sur le DAG (capture d'écran ci-dessus).

5. Déplacer les bases de données actives vers un autre membre du DAG

Jusqu'à présent, nous nous sommes occupés des services Transport et du cluster. Il nous reste encore un certain nombre de tâches à accomplir et en particulier le déplacement des copies actives vers un autre membre du DAG. Nous y parvenons avec cette commande : 

Set-MailboxServer EX16-4 -DatabaseCopyActivationDisabledAndMoveNow $True

Attention ! Il faut un moment (quelques minutes au moins) pour que le déplacement s'achève. Quand j'ai exécuté la commande...

Get-MailboxDatabase | Get-MailboxDatabaseCopyStatus

une première fois, la copie active se trouvait toujours sur EX16-4. Il a fallu attendre encore quelques minutes avant d'observer le résultat désiré :

6. Bloquer la possibilité d'activation 

Comme pour les services de cluster, nous devons empêcher la copie active de revenir au serveur EX16-4 pendant la maintenance, ce qu'accomplit cette commande :

Set-MailboxServer EX16-4 -DatabaseCopyAutoActivationPolicy Blocked

7. Mettre le serveur en mode maintenance (services Accès client)

C'est ainsi que certaines sources décrivent cette dernière étape bien que le processus de mise en maintenance ait réellement commencé plus tôt. Voici la commande à exécuter :

Set-ServerComponentState EX16-4 -Component ServerWideOffline -State Inactive -Requester Maintenance

Cette commande agit notamment sur les services Accès client (CAS). Le serveur, mis en mode maintenance, ne répond plus, en principe, aux messages de vie des répartiteurs de charge (load balancer heart beats).

En fait, cette commande ne semble rien changer si on considère l'état des services vu de mon répartiteur de charge (Citrix NetScaler VPX) :

Quant aux services Transport, nous devrions veiller à ce que les files d'attente soient effectivement purgées. Mais qu'arriverait-il aux messages encore dans les files d'attente après l'exécution de cette commande ? Les messages en cours de traitement par les services Transport sont stockés dans une base de données. A priori, ils y seraient retenus pendant l'arrêt du service Transport et traités seulement à la remise en marche de celui-ci. Ils ne seraient pas perdus comme s'ils n'existaient que dans la mémoire vive.

Quoi qu'il en soit, nous vérifions l'effet de cette dernière commande avec sa variation "Get" :

Get-ServerComponentState EX16-4

Toutes les composantes, sauf "Monitoring" et "RecoveryActionEnabled" devraient avoir, pour la propriété "State" (état), la valeur "Inactive" :


A cette étape, nous pouvons (enfin) accomplir ce que nous avons à faire (installer des mises à jour de sécurité, par exemple).

Dans les lignes ci-dessus, j'ai cherché non seulement à présenter la marche à suivre mais aussi à vérifier pour moi-même si les commandes ont l'effet escompté. Il en résulte que le texte s'est allongé plus que je m'y attendais. De ce fait, je remets à plus tard la présentation de la remise en ligne du serveur.


Managing database availability groups - Exchange 2016

C'est la version anglaise originale.

La procédure présentée dans ce texte consiste...
  1. A exécuter certaines des commandes que j'ai utilisées plus haut.
  2. A exécuter le script StartDagServerMaintenance.ps1 (nommé à tort "StartDagServerMaintenanceScripts.ps1") comme avec Exchange 2010.
  3. A exécuter encore d'autres commandes utilisées dans mon billet de blogue ici.

En traduction française :

Gestion de groupes de disponibilité de base de données


Exchange 2013 Maintenance mode

La procédure est valable pour Exchange 2016 mais j'ai remarqué que la commande Suspend-ClusterNode ne déplace pas le PAM vers un autre membre du DAG. Il faut d'abord utiliser la commande Move-ClusterGroup.


Installing Cumulative Updates on Exchange Server 2016 - Paul Cunningham

Le sujet concerne l'installation des mises à jour mais l'auteur (fort respecté dans la communauté Exchange) présente sa façon de mettre les serveurs en mode maintenance.

Sunday, June 11, 2017

Exchange 2016 (23) : récupération d'un serveur membre d'un DAG (3)

English summary: after reinstalling our failed Exchange 2016 server with the /recoverserver parameter, reconfiguring the client access Urls and the SSL certificate (see previous blog post), we readd the recovered server to the DAG and create a copy of the MBXDB-01 database on the recovered server. Various functions are tested (client access, send/receive email) and we consider the interaction with our load balancer. Lastly, I point out that there may be other elements to reinstall and reconfigure such as the antivirus and backup programs


Maintenant que le serveur EX16-3 est remis sur pied, nous sommes prêts à le rajouter à notre DAG et à lui ajouter une copie de la base de données MBXDB-01.

Voici notre point de départ...

Seul le serveur EX16-4 fait partie du DAG en ce moment :

Les lecteurs E: et F: du serveur EX16-3 sont vides :

Voici, par exemple, le contenu du lecteur E: (rien) :

Si nous mettons de côté la base de donnée MBXDB-03 (qui ne joue aucun rôle dans cet exercice), nous pouvons observer que la base de données MBXDB-01 ne compte qu'une seule copie qui se trouve sur le serveur EX16-4 :

Rajouter le serveur au DAG

Maintenant, nous allons rajouter le serveur récupéré, EX16-3, au DAG avec la commande suivante :

Add-DatabaseAvailabilityGroupServer DAG1 -MailboxServer EX16-3

Nous devrions voir les opérations affichées à mesure qu'elles se réalisent :

Note : oui, c'est au serveur EX16-4 que je me trouve et où j'exécute la commande qui cible bel et bien le serveur EX16-3.

Les résultats sont observables tout de suite. Notre DAG compte de nouveau deux serveurs :

Ajouter une copie de la base de données à EX16-3

Maintenant que le serveur récupéré (EX16-3) fait de nouveau partie du DAG, nous sommes en mesure d'ajouter une copie des bases de données à répliquer. Dans notre cas, il s'agit de la base de données MBXDB-01. Il n'est pas obligatoire de faire une copie de toutes nos bases de données sur tous les serveurs membres du DAG. Nous avons, par exemple, une autre base de données, MBXDB-03, et nous n'en garderons qu'une seule copie.

Nous ajoutons donc une copie de la base de données MBXDB01 sur EX16-3 avec la commande suivante :

Add-MailboxDatabaseCopy MBXDB-01 -MailboxServer EX16-3

Note : l'avertissement en caractères jaunes concernent les permissions sur les répertoires qui viennent d'être créés. Il est recommandé de créer les répertoires au préalable pour avoir les permissions les plus sûres. Je ne vais pas traiter de cette question ici.

Si tout se passe bien, nous devrions avoir vu les opérations se réaliser en haut de l'écran :


En outre, nous pouvons observer  le progrès des données copiées vers EX16-3. La file d'attente où les données attendent d'être copiées décroît en nombre pour enfin arriver à zéro :

Quant à l'état de l'index du contenu, il est "en échec". J'ai essayé de le réparer avec la commande suivante :

Update-MailboxDatabaseCopy MBXDB-01\EX16-3 -CatalogOnly

Mais son état n'a pas changé tout de suite et il a fallu attendre encore un moment avant que tout rentre dans l'ordre :

Peut-être fallait-il simplement faire preuve de plus de patience ? Je me suis demandé si l'état de l'index serait redevenu normal sans la commande Update-MailboxDatabaseCopy ?

En tout cas, les lecteurs E: et F: qui étaient vides au départ contiennent désormais une copie de la base de données et les fichiers des journaux de transaction respectivement :

Voici l'exemple du lecteur E:

Les répertoires ont été créés de façon automatique sans intervention manuelle aucune. Cependant, il paraît que le processus n'ajuste pas les permissions selon les recommandations que nous avons vues dans les avertissements en caractères jaunes plus haut.


Nous avons rétabli notre DAG mais est-il vraiment en état de marche ? Les commandes exécutées plus haut semblent le confirmer mais pouvons-nous rendre la base de données MBXDB-01 active sur EX16-3 avec succès ? Je fais le changement avec cette commande :

Move-ActiveMailboxDatabase MBXDB-01 -ActivateOnServer EX16-3

Je confirme l'état de la base de donnée (et ses copies) avec cette commande :

Get-MailboxDatabase | Get-MailboxDatabaseCopyStatus

Ensuite, je vérifie que mes utilisateurs peuvent accéder à leur boîte aux lettres, envoyer et recevoir des messages, à la fois entre eux et avec des correspondants à l'extérieur. Nous avons déjà vu dans le texte précédent que si nous devons remplacer les Urls et le certificat SSL pour le service Accès client, les services Transport s'étaient rétablis sans intervention manuelle au cours de l'installation du serveur, grâce au paramètre /recoverserver.


Dans la plupart des réseaux, Exchange ne fonctionne pas tout seul (sans même compter l'interaction nécessaire avec Active Directory). Il faudrait sans doute réinstaller, par exemple, un logiciel d'antivirus et de sauvegarde. Il arrive aussi que le système de messagerie recourt à un répartiteur de charge. Dans le scénario de panne et de récupération que j'ai mis en scène ici, le basculement s'est fait sans mal et l'utilisateur d'Outlook n'a remarqué qu'une courte déconnexion (une minute au plus ? ). Il faut penser que le répartiteur a bien géré la panne de son côté aussi.

A ce sujet, je voulais prendre note de l'état des éléments concernant mes serveurs Exchange lors de la panne, afin de savoir ce qui est normal dans une telle situation. Bien entendu, l'interface de chaque répartiteur varie. Ce qui suit montre les effets de la panne d'un serveur Exchange vus de la perspective de mon répartiteur (Citrix NetScaler VPX v. 11).

Dans la section "Servers", rien ne change. Les "voyants" restent verts :

Dans la section "Virtual Servers", tout est au vert, sans doute parce qu'au moins un des serveurs est en état de marche et capable de fournir le service en question (HTTPS, SMTP). C'est seulement si nous regardons de plus près, dans la colonne " % Health " que nous voyons qu'un des deux serveurs manque à l'appel :

Dans la section "Services", nous avons une vue plus détaillée de ceux-ci et nous voyons que c'est EX16-3 (le serveur en panne) qui ne fournit plus le service en question (HTTPS et SMTP dans notre configuration) :


Bien entendu, après la récupération d'EX16-3, tous les voyants sont verts de nouveau.

De plus, je n'ai été obligé de prendre aucune action sur le répartiteur de charge. Quand le serveur en panne était remis sur pied, les communications avec le répartiteur ont repris automatiquement.