Monday, October 13, 2014

Exchange 2010 - DAG (Database Availability Group) - corrupted search catalog - reseed

Sometimes elements of a mailbox database can become damaged or "corrupt".

One advantage of the DAG is that we can "reseed" the damaged copy of the database using the remaining good copy (or one of the good copies if there are more than two DAG nodes). In other words, we essentially overwrite the bad data with good data.

Recently, I had to recover from a "corrupted search catalog".

This is what appeared in the Application Log of the Event Viewer:


EventID: 123
Source: ExchangeStoreDB
Level: Error

At '[date and time here]' the Microsoft Exchange Information Store Database 'DB1' copy on this server experienced a corrupted search catalog. Consult the event log on the server for other "ExchangeStoreDb" and "MSExchange Search Indexer" events for more specific information about the failure. Reseeding the catalog is recommended via the 'Update-MailboxDatabaseCopy' task.


The description mentions the action to take: reseed the catalog with the Update-MailboxDatabaseCopy cmdlet.

This cmdlet typically overwrites the entire database (which would be appropriate if the entire database was damaged). This might seem excessive when only the search catalog is affected.

Fortunately... there is a -CatalogOnly parameter.

Update-MailboxDatabaseCopy DB1\EX13-2 -CatalogOnly


I thought it might be necessary to suspend replication, as is the case for a complete database reseed. This may not be the case. Such an operation is mentioned in the documentation for database updates in general but not for catalog only updates in particular. I thought I would attempt to reseed the catalog directly (without suspending replication):


[PS] C:\>Update-MailboxDatabaseCopy DB1\EX13-2 -CatalogOnly

This operation apparently completed: there was no error message - or any message at all. Usually, with Powershell, this means that everything is OK.


If it was necessary to suspend replication, this is the command:

[PS] C:\>Suspend-MailboxDatabaseCopy DB1\EX13-2

We confirm when prompted and then execute this command (the same as above):

[PS] C:\>Update-MailboxDatabaseCopy DB1\EX13-2 -CatalogOnly

We can then resume replication:

[PS] C:\>Resume-MailboxDatabaseCopy DB1\EX13-2


References:

EventID 123 - ExchangeStoreDB

Reseed the Search Catalog

Update-MailboxDatabaseCopy

Suspend or Resume a Mailbox Database Copy

Sunday, October 12, 2014

FR (French) - Powershell 4.0 - Active Directory management - Organizational Units

English - note to reader: as I'm bilingual, I wanted to write a series of blog posts about Active Directory management with Powershell (4.0) - but in French. I intend to continue blogging in English as well, perhaps with a hybrid migration to Exchange Online - Office 365 (after the staged migration that you can find in my previous posts).

In the title of the blog post, I'll add the prefix "FR (French)" to distinguish them from my posts in English.

Feel free to translate the page with Google Translate or make comments if you'd like me to clarify something (in French or in English).

Google Translate

***

Créer une UO

La création d'une UO (unité d'organisation - OU en anglais) est simple. Si nous n'avons rien de plus à préciser (une description, par exemple), nous pouvons le faire avec l'applet suivant :

New-ADOrganizationalUnit "Laptops"

Par défaut, les UO sont protégées contre la suppression accidentelle. Si nous voulions que l'on puisse les supprimer plus facilement, nous pourrions désactiver cette protection ainsi :

New-ADOrganizationalUnit "Desktops" -ProtectedFromAccidentalDeletion:$false



Protéger une UO contre la suppression accidentelle

Si nous voulons protéger une UO (ou un autre objet) non-protégée, nous pouvons activer la protection avec l'applet suivant :

Set-ADOrganizationalUnit "OU=Desktops,DC=mynet,DC=lan" -ProtectedFromAccidentalDeletion:$true



Afficher les propriétés d'une UO

A la différence d'autres objets, si nous voulons afficher les propriétés d'une UO, nous devons mettre le nom distingué (DN).

Par exemple, ceci ne donne rien :

Get-ADOrganizationalUnit "Laptops"

Get-ADOrganizationalUnit : Cannot find an object with identity: 'Laptops' under: 'DC=mynet,DC=lan'.

Contrairement à l'applet Get-ADUser :

Get-ADUser Vik.Kirby

DistinguishedName : CN=Vik.Kirby,OU=ExchangeUsers,DC=mynet,DC=lan
Enabled           : True
GivenName     : Vik
Name              : Vik.Kirby
[...]


En outre, si nous voulons afficher toutes les propriétés d'un objet (ceci est valable pour d'autres objets), il faut indiquer -properties *.

Dans ce cas, je veux afficher le nom et la valeur du paramètre "ProtectedFromAccidentalDeletion" mais ceci ne donne rien de plus que le nom :

Get-ADOrganizationalUnit "OU=Laptops,dc=mynet,dc=lan" | fl name,*protect*

name : Laptops


Mais si j'ajoute -propreties * ou même -prop *, j'ai l'élément que je voulais :

Get-ADOrganizationalUnit "OU=Laptops,dc=mynet,dc=lan" -prop * | fl name,*protect*

name                            : Laptops
ProtectedFromAccidentalDeletion : True




Dresser la liste des UO dans le domaine

Get-ADOrganizationalUnit -filter * | fl name

name : Domain Controllers
name : Microsoft Exchange Security Groups
name : ExchangeUsers
name : Servers
name : Laptops
name : Desktops

Remarquons qu'il faut mettre le paramètre -filter, quitte à ne mettre qu'un astérisque après. Sinon, PowerShell nous demandera des précisions :

Get-ADOrganizationalUnit | fl name

cmdlet Get-ADOrganizationalUnit at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Filter:

Il en va de même d'ailleurs pour Get-ADUser, Get-ADGroup et Get-ADComputer :

cmdlet Get-ADUser at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Filter: PS C:\>

cmdlet Get-ADGroup at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Filter: PS C:\>

cmdlet Get-ADComputer at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
Filter:

Encore une fois, si je veux afficher les propriétés aussi, je dois ajouter -properties *

Note : je mets en raccourci -prop *, ce que PowerShell admet.

Get-ADOrganizationalUnit -prop * -filter * | fl name,*prot*

[...]

name                            : Laptops
ProtectedFromAccidentalDeletion : True

name                            : Desktops
ProtectedFromAccidentalDeletion : True



Dresser la liste des objets contenus dans une UO

Si nous ne savons pas quel type d'objet se trouve dans l'UO, nous pouvons les afficher tous avec la commande suivante. Je limite la recherche à l'UO "Lyon" avec le paramètre -SearchBase.


Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -filter * | select name,objectClass | ft -auto

name                    objectClass
----                        -----------
Lyon                   organizationalUnit
John.Thompson  user
Kathy.Zuiker      user
PC5                    computer
Accounting        group
Jane.Martin        user


Note : "select" (Select-Object) a pour effet de n'afficher que les propriétés d'objet qui m'intéressent. "ft" (Format-Table) présente les données d'une certaine façon.



Compter le nombre d'objets dans une UO

Il s'agit ici de les compter littéralement au lieu d'en dresser la liste. C'est l'applet Measure-Object qui nous permet de le faire :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -filter * | Measure-Object

Count    : 6
[...]

Ce compte inclut l'UO elle-même ainsi que les objets énumérés dans l'exemple précédent : trois utilisateurs, un groupe et un ordinateur.

Si nous voulons ne pas compter le conteneur, nous pouvons recourir au paramètre -SearchScope et indiquer "OneLevel" :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -SearchScope OneLevel -filter * | Measure-Object

Count    : 5
[...]



Déplacer des objets entre deux UO

Si nous voulons déplacer les objets contenus dans une UO vers une autre, il est essentiel de bien cerner l'étendue de la recherche, comme dans l'exemple ci-dessus. Sinon, PowerShell inclura le conteneur (l'UO) lui-même et passera cet objet aussi à l'applet Move-ADObject. Cela pose plusieurs problèmes. D'abord, nous ne voulons sans doute pas déplacer l'UO elle-même à l'intérieur d'une autre UO. Ensuite, une opération de déplacement ("move") signifie, en fait, que l'objet à déplacer est copié dans le nouvel emplacement et supprimé dans l'emplacement d'origine. Or, les UO sont protégées contre la suppression et l'opération échouera. Si on tenait vraiment à déplacer l'UO, il faudrait désactiver cette protection au préalable.

Voici un exemple :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -filter * | Move-ADObject -TargetPath "OU=Nice,DC=mynet,DC=lan"

Move-ADObject : Access is denied

Nous pouvons écarter cet obstacle en précisant l'étendue ("scope") de la recherche comme ceci :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -SearchScope OneLevel -filter * | Move-ADObject -TargetPath "OU=Nice,DC=mynet,DC=lan"



Filtrer les résultats selon le type d'objet

Si nous souhaitons afficher les objets contenus dans l'UO en fonction de leur type, nous pouvons remplacer l'astérisque après le paramètre -filter par le type d'objet.

Voici les résultats sans filtre :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -SearchScope OneLevel -filter * | select name,objectClass | ft -auto

name             objectClass
----                 -----------
Jane.Martin        user
John.Thompson user
Kathy.Zuiker     user
PC5                   computer

Note: le groupe "Accounting" n'y figure plus (il a été déplacé). L'UO elle-même n'y figure pas non plus en raison du paramètre -SearchScope et de la valeur "OneLevel".

Maintenant, nous allons rechercher seulement les objets de type "user" :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -filter {ObjectClass -eq "User"} | select name,objectClass | ft -auto

name                  objectClass
----                       -----------
John.Thompson   user
Kathy.Zuiker       user
PC5                     computer
Jane.Martin         user

A notre grande surprise (peut-être), la recherche retourne aussi un ordinateur (PC5). C'est parce que la classe "computer" est en fait une sous-classe de la classe "user".

Afin d'exclure les ordinateurs, nous devons affiner notre filtrage :

Get-ADObject -SearchBase "OU=Lyon,DC=mynet,DC=lan" -filter {(ObjectClass -eq "User") -and (ObjectCategory -eq "Person")} | select name,objectClass | ft -auto

name                objectClass
----                     -----------
John.Thompson  user
Kathy.Zuiker      user
Jane.Martin        user

Friday, October 10, 2014

FR (French) - Powershell 4.0 - Active Directory management - Remove-ADObject

Si nous voulons supprimer un objet (utilisateur, groupe, ordinateur ou unité d'organisation, par exemple), nous pouvons recourir à l'applet Remove-ADObject.

L'applet fonctionne plus ou moins de la même manière quel que soit l'objet.

Nous pouvons soit désigner l'objet directement avec le nom distingué (DN) comme dans l'exemple de l'ordinateur XP2 ci-dessous, soit utiliser Get-ADUser, Get-ADGroup ou Get-ADComputer pour désigner l'objet et seulement ensuite le supprimer avec l'applet Remove-ADObject. C'est l'exemple de l'utilisateur Katherine Phipps ci-dessous.


Dans ce premier exemple, je vais tenter de supprimer un objet dans l'unité d'organisation "XP_Clients" et puis l'unité d'organisation elle-même...

PS C:\> Remove-ADObject "cn=XP2,ou=XP_Clients,dc=mynet,dc=lan" -confirm:$false

La commande réussit. J'évite de devoir confirmer l'opération en ajoutant le paramètre facultatif -confirm avec la valeur $false.

Mais la tentative de supprimer l'unité d'organisation elle-même échoue en raison des objets qu'elle contient. C'est une sorte de garde-fou qui nous empêche de supprimer par mégarde des centaines ou des milliers d'objets-enfants. Nous devons mettre le paramètre -recursive en plus pour réussir cette opération:

PS C:\> Remove-ADObject "ou=XP_Clients,dc=mynet,dc=lan" -confirm:$false
Remove-ADObject : The operation cannot be performed because child objects exist.[...]

PS C:\> Remove-ADObject "ou=XP_Clients,dc=mynet,dc=lan" -recursive -confirm:$false


***

Supprimer un simple utilisateur est sans doute le plus simple. Si le paramètre -confirm égale $false, une seule ligne suffit :

PS C:\> Get-ADUser Katherine.Phipps | Remove-ADObject -confirm:$false

***

Nous pouvons supprimer des unités d'organisation comme les autres objets mais éventuellement après avoir désactivé la protection contre la suppression accidentelle (activée par défaut à la création d'une UO) : 

PS C:\> Get-ADOrganizationalUnit "OU=DELETE,DC=mynet,DC=lan" | Remove-ADObject -confirm:$false

Remove-ADObject : Access is denied [...].

PS C:\> Set-ADOrganizationalUnit "OU=DELETE,DC=mynet,DC=lan" -ProtectedFromAccidentalDeletion:$false

PS C:\> Get-ADOrganizationalUnit "OU=DELETE,DC=mynet,DC=lan" | Remove-ADObject -confirm:$false

Monday, October 6, 2014

FR (French) - Powershell 4.0 - Active Directory management - Rename-ADObject

English - note to reader: as I'm bilingual, I wanted to write a series of blog posts about Active Directory management with Powershell (4.0) - but in French. I intend to continue blogging in English as well, perhaps with a hybrid migration to Exchange Online - Office 365 (after the staged migration that you can find in my previous posts).

In the title of the blog post, I'll add the prefix "FR (French)" to distinguish them from my posts in English.

Feel free to translate the page with Google Translate or make comments if you'd like me to clarify something (in French or in English).


***

Si nous voulons renommer un object Active Directory, il faut, comme dans l'interface graphique, le faire en plusieurs endroits. Le cas d'un utilisateur est le plus complexe.



Renommer un utilisateur

Pour cet exemple, j'ai un utilisateur nommé Salma Green. Nous allons la renommer "Salma Brown" (le prénom reste donc le même).

Voici notre point de départ :

PS C:\> Get-ADUser Salma.Green

DistinguishedName : CN=Salma.Green,OU=ExchangeUsers,DC=mynet,DC=lan
Enabled           : True
GivenName         : Salma
Name              : Salma.Green
ObjectClass       : user
ObjectGUID        : 9fc147de-7c49-4b5d-b1c4-b0b590e05acb
SamAccountName    : Salma.Green
SID               : S-1-5-21-326661974-301178600-1381666802-1444
Surname           : Green
UserPrincipalName : Salma.Green@mynet.lan


Essayons donc de la renommer avec cet applet:

PS C:\> Rename-ADObject "cn=Salma.Green,ou=ExchangeUsers,dc=mynet,dc=lan" -NewName Salma.Brown

Et regardons le résultat :

PS C:\> Get-ADUser Salma.Green

DistinguishedName : CN=Salma.Brown,OU=ExchangeUsers,DC=mynet,DC=lan
Enabled           : True
GivenName         : Salma
Name              : Salma.Brown
ObjectClass       : user
ObjectGUID        : 9fc147de-7c49-4b5d-b1c4-b0b590e05acb
SamAccountName    : Salma.Green
SID               : S-1-5-21-326661974-301178600-1381666802-1444
Surname           : Green
UserPrincipalName : Salma.Green@mynet.lan

La commande change le nom distingué (DistinguishedName - DN) et le nom (Salma.Brown) mais c'est tout.


Trois noms restent les mêmes :

SamAccountName    : Salma.Green
Surname           : Green
UserPrincipalName : Salma.Green@mynet.lan


En outre, j'observe que l'applet Get-ADUser retourne toujours des données pour "Salma.Green" et donc semble dépendre non pas de "Name" mais plutôt du SamAccountName. C'est pourquoi je peux taper Get-ADUser Salma.Green et obtenir le même résultat malgré le changement de (certains) noms.

Comment changer les autres paramètres (les autres noms) ?

Essayons maintenant ceci :

PS C:\> Get-ADUser Salma.Green | Set-ADUser -Surname Brown -sAMAccountName Salma.Brown -UserPrincipalName Salma.Brown@mynet.lan

Désormais, la cmdlet Get-ADUser Salma.Green ne retourne aucun résultat:

PS C:\> Get-ADUser Salma.Green
Get-ADUser : Cannot find an object with identity: 'Salma.Green' under: 'DC=mynet,DC=lan'.

Mais si nous faisons une requête pour Salma.Brown, nous avons un résultat et nous pouvons constater que tous les paramètres ont été renommés :

DistinguishedName : CN=Salma.Brown,OU=ExchangeUsers,DC=mynet,DC=lan
Enabled           : True
GivenName         : Salma
Name              : Salma.Brown
ObjectClass       : user
ObjectGUID        : 9fc147de-7c49-4b5d-b1c4-b0b590e05acb
SamAccountName    : Salma.Brown
SID               : S-1-5-21-326661974-301178600-1381666802-1444
Surname           : Brown
UserPrincipalName : Salma.Brown@mynet.lan

Nous remarquons aussi (voir les exemples ci-dessus) que le SID et l'objectGUID ne changent pas.

Note: il pourrait y avoir encore d'autres paramètres à renommer, si, par exemple, nous utilisions Exchange pour la messagerie et si nous avions donc une adresse à changer.


Renommer un groupe

C'est plus simple que pour l'utilisateur mais il faut, pour le groupe aussi, modifier plus d'un paramètre.

PS C:\> Get-ADGroup "Human Resources"

DistinguishedName : CN=Human Resources,OU=Berlin,DC=mynet,DC=lan
GroupCategory     : Security
GroupScope        : Global
Name              : Human Resources
ObjectClass       : group
ObjectGUID        : ceedc833-14fb-4e81-a1a8-9dd7351ec30e
SamAccountName    : Human Resources
SID               : S-1-5-21-326661974-301178600-1381666802-2653


Nous utilisons le même applet que pour l'utilisateur, sauf que nous ciblons un objet de type "groupe" :

PS C:\> Rename-ADObject "CN=Human Resources,OU=Berlin,DC=mynet,DC=lan" -newname HR


Comme pour l'utilisateur, l'applet ci-dessus ne change pas tous les paramètres :

PS C:\> Get-ADGroup "Human Resources"

DistinguishedName : CN=HR,OU=Berlin,DC=mynet,DC=lan
GroupCategory     : Security
GroupScope        : Global
Name              : HR
ObjectClass       : group
ObjectGUID        : ceedc833-14fb-4e81-a1a8-9dd7351ec30e
SamAccountName    : Human Resources
SID               : S-1-5-21-326661974-301178600-1381666802-2653

Encore une fois, comme pour l'utilisateur, Rename-ADObject change le paramètre "name" (nom) mais non pas le paramètre "SamAccountName"

Nous devons exécuter cet applet pour achever le changement de nom :

PS C:\> Set-ADGroup "CN=HR,OU=Berlin,DC=mynet,DC=lan" -SamAccountNam "HR"

Ce qui nous donne ceci :

PS C:\> Get-ADGroup HR

DistinguishedName : CN=HR,OU=Berlin,DC=mynet,DC=lan
GroupCategory     : Security
GroupScope        : Global
Name              : HR
ObjectClass       : group
ObjectGUID        : ceedc833-14fb-4e81-a1a8-9dd7351ec30e
SamAccountName    : HR
SID               : S-1-5-21-326661974-301178600-1381666802-2653

J'ai remarqué qu'aucun des applets suivants n'a pu renommer le paramètre "SamAccountName" :

PS C:\> Set-ADObject "HR" -sAMAccountName HR
PS C:\> Set-ADObject "HR" -SamAccountName "HR"
PS C:\> Set-ADObject "HR" @{SamAccountName="HR"}
PS C:\> Set-ADObject "CN=HR,OU=Berlin,DC=mynet,DC=lan" -SamAccountName "HR"



Renommer un ordinateur

C'est comparable aux autres objets :

PS C:\> Get-ADComputer PC3 | Rename-ADObject -newname PC4

PS C:\> Get-ADComputer PC3

DistinguishedName : CN=PC4,OU=Clients,DC=mynet,DC=lan
DNSHostName       :
Enabled           : True
Name              : PC4
ObjectClass       : computer
ObjectGUID        : 816a8176-c433-401c-a812-ad2d7a0ed3c6
SamAccountName    : PC3$
SID               : S-1-5-21-326661974-301178600-1381666802-2656
UserPrincipalName :

Comme pour les groupes, l'applet ne modifie pas le paramètre "SamAccountName", ce que nous pouvons corriger ainsi :

PS C:\> Get-ADComputer PC3 | Set-ADComputer -SamAccountName PC4$
PS C:\>
PS C:\> Get-ADComputer PC4

DistinguishedName : CN=PC4,OU=Clients,DC=mynet,DC=lan
DNSHostName       :
Enabled           : True
Name              : PC4
ObjectClass       : computer
ObjectGUID        : 816a8176-c433-401c-a812-ad2d7a0ed3c6
SamAccountName    : PC4$
SID               : S-1-5-21-326661974-301178600-1381666802-2656
UserPrincipalName :


Le paramètre "SamAccountName" est suivi toujours par un "$" (et sans espace). Quand nous modifions ce paramètre nous pouvons l'ajouter ou bien l'omettre. Dans ce cas-ci,  le $ est ajouté automatiquement:

PS C:\> Get-ADComputer PC4 | Set-ADComputer -SamAccountName PC8

PS C:\> Get-ADComputer PC8

DistinguishedName : CN=PC8,OU=Clients,DC=mynet,DC=lan
DNSHostName       :
Enabled           : True
Name              : PC8
ObjectClass       : computer
ObjectGUID        : 816a8176-c433-401c-a812-ad2d7a0ed3c6
SamAccountName    : PC8$
SID               : S-1-5-21-326661974-301178600-1381666802-2656
UserPrincipalName :




Renommer une unité d'organisation (OU)

C'est sans doute le cas le plus simple

PS C:\> Get-ADOrganizationalUnit "OU=Administration,DC=mynet,DC=lan"

[...]
DistinguishedName        : OU=Administration,DC=mynet,DC=lan
LinkedGroupPolicyObjects : {}
ManagedBy                :
Name                     : Administration
ObjectClass              : organizationalUnit
ObjectGUID               : 8044c557-73e3-4b56-aa49-17e8812b56d7
[...]

PS C:\> Get-ADOrganizationalUnit "OU=Administration,DC=mynet,DC=lan" | Rename-ADObject -newname Management

PS C:\> Get-ADOrganizationalUnit "OU=Management,DC=mynet,DC=lan"

[...]
DistinguishedName        : OU=Management,DC=mynet,DC=lan
LinkedGroupPolicyObjects : {}
ManagedBy                :
Name                     : Management
ObjectClass              : organizationalUnit
ObjectGUID               : 8044c557-73e3-4b56-aa49-17e8812b56d7
[...]


Ainsi, nous pouvons renommer l'OU en une seule opération.