PI Services

Le blog des collaborateurs de PI Services

SCOM - Script - Supprimer ou Mettre en mode maintenance un/des agent selon la valeur d'une propriété (Nouvelle version)

Le script suivant est une nouvelle version d'un script récemment proposé. Ont été rajouté le choix entre suppression et mode maintenance (on verifie aussi que la machine est déjà en mode maintenance)

 

DeleteOrMaintenanceAgentUponPropertyValue.ps1 (14,85 kb)

 

## DeleteOrMaintenanceAgentUponPropertyValue.ps1
## SCOM - REMOVE FROM CONSOLE OR PUT IN MAINTENANCE MODE, AGENT(S) THAT HAVE SPECIFIC VALUES IN ONE OR MORE CLASS PROPERTY.
## AUTHOR: C.JOURDAN
## Version: 1.1

##  PARAMETERS
##  $MS: Target Management Server
##  $ObjectClass: Display Name of Target Class
##  $FirstProperty: name of class property
##  $FirstPropVal: multi value possible of $FirstProperty
##  $Action: DELETE or MAINTENANCE
##  $MaintenanceDuration: Nb of minutes for Maintenance Mode
##  $ThreshNotDelete: Nb of found computers to delete over which we only warn (NO AUTOMATIC DELETE)

## NOTES: $ThreshNotDelete PARAMETER IS A SECURITY OPTION TO AVOID DELETION OF TWO MANY AGENTS. BE SURE OF THE APPLIED CRITERIAS BEFORE UNLOCK THAT! 


#PARAMETERS
Param(
[Parameter(Mandatory=$false)]
$MGroup,
[Parameter(Mandatory=$false)]
$MS="MyMS",
[Parameter(Mandatory=$false)]
$ObjectClass="MyClass",
[Parameter(Mandatory=$false)]
$FirstProperty='MyProperty',
[Parameter(Mandatory=$false)]
$FirstPropVal="^.*(AZERTY|QWERTY).*$",
<# -- ADDITIONAL PROPERTIES FROM $ObjectClass INSTANCE -- SEE CLASS INSTANCE RETRIEVE SECTION
[Parameter(Mandatory=$false)]
$SecondProperty='Prop2',
[Parameter(Mandatory=$false)]
$SecondPropVal='Value2'
#>
[Parameter(Mandatory=$false)]
$Action = "Maintenance",
[Parameter(Mandatory=$false)]
$MaintenanceDuration = 30,
[Parameter(Mandatory=$false)]
$ThreshNotDelete = 10
)

#ScriptName
$ScriptName = "DeleteOrMaintenanceAgentUponPropertyValue.ps1"



#FUNCTIONS

# NewEventSource
# Check of a source existance  in the 'operation manager' eventlog that match the script name, to log some events.
         Function NewEventSource 
         { 
         if(!(Test-Path "HKLM:\SYSTEM\CurrentControlSet\services\eventlog\Operations Manager\$ScriptName")) 
         { 
         New-EventLog -LogName "Operations Manager" -Source $ScriptName 
         }
         } 


# DeleteSCOMAgent
# Remove agent from SCOM Console.
Function DeleteSCOMAgent 
{
Param(
  [string[]]$AgentComputerName,
  [string]$MSServer
)

[System.Reflection.Assembly]::Load("Microsoft.EnterpriseManagement.Core, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
[System.Reflection.Assembly]::Load("Microsoft.EnterpriseManagement.OperationsManager, Version=7.0.5000.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")



function New-Collection ( [type] $type ) 
{
	$typeAssemblyName = $type.AssemblyQualifiedName;
	$collection = new-object "System.Collections.ObjectModel.Collection``1[[$typeAssemblyName]]";
	return ,($collection);
}




# Connect to management group
Write-output "Connecting to management group "$ConnectionSetting.name""

$ConnectionSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MSServer)
$admin = $ConnectionSetting.GetAdministration()


Write-output "Getting agent managed computers"
$agentManagedComputers = $admin.GetAllAgentManagedComputers()

# Get list of agents to delete
foreach ($name in $AgentComputerName) 
{
    Write-output "Checking for $name"
    foreach ($agent in $agentManagedComputers)
    {
        if ($deleteCollection -eq $null) 
        {
            $deleteCollection = new-collection $agent.GetType()
        }

        
        if (@($agent.PrincipalName -eq $name))
        {
	    Write-output "Matched $name"
            $deleteCollection.Add($agent)
            break
        }
    }
}

if ($deleteCollection.Count -gt 0) 
{
    Write-output "Deleting agents"
    $admin.DeleteAgentManagedComputers($deleteCollection)
    if($?){
           $Script:result="Agents deleted"
           Write-Output $result
          }
    Else  {
           $result="Error during deletion of one ore more agent"
           Write-Output $result
          }
}

Else
    {
    $result="No Agent found to delete"
    Write-Output $result
    }


}


Function SetMM
{
# Function SetMM 
########################################################################
# 
#
[CmdletBinding()]

param(
  [string]$HostToMM,
  [string]$Duration
)

$startTime = [DateTime]::Now
$endTime = $startTime.AddMinutes($Duration)

    # Get "Microsoft.Windows.Computer" Class
    $Class = get-SCOMclass | where-object {$_.Name -eq "Microsoft.Windows.Computer"};

    $Instance = Get-SCOMClassInstance -Class $Class | Where-Object {$_.Displayname -like "$HostToMM*"};
    
    Start-SCOMMaintenanceMode -Instance $Instance -Reason "PlannedOther" -EndTime $endTime -Comment "PLANNED BY SCOM AGENT REMOVER" -ErrorAction Stop
    
    
}



#END FUNCTIONS



#Log of script execution 
NewEventSource
$message =  "Execution du script $ScriptName"
$message
write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 999 -Message $message -EntryType Information 


# Check if $Action is valid
if ($Action -notmatch "^delete|maintenance$")
    {
    $message = "NO VALID ACTION HAS BEEN CHOOSED - POSSIBLE VALUE: `"DELETE`" OR `"MAINTENANCE`""
    write-host -ForegroundColor Yellow $message
    NewEventSource 
    write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1000 -Message $message -EntryType Warning
    exit 1
    }



#Import of SCOM Powershell module
try
{
Import-Module -Name OperationsManager -ErrorAction stop
}
catch
{
$message = "ERROR DURING IMPORT OF SCOM PS MODULE"
write-host -ForegroundColor red $message
NewEventSource 
write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1001 -Message $message -EntryType Error 
exit 1 
}



#Connection to management group $MGroup
try
{
New-SCOMManagementGroupConnection -ComputerName $MS
}
catch
{
$message = "ERROR DURING CONNECTION TO $MS"
write-host -ForegroundColor red $message
NewEventSource 
write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1002 -Message $message -EntryType Error 
exit 1 
}


# Get $ObjectClass Class
$Class = Get-SCOMClass -displayname $ObjectClass | Where-Object {$_.PropertyCollection -match "^.*($FirstProperty|$SecondProperty).*$"} -ErrorAction stop    ## -- WE CHECK THAT THE TARGET CLASS REALLY HOLD THE WANTED PROPERTIES
if (!($Class))
{
$message = "ERROR DURING RETRIEVE OF '$ObjectClass' CLASS. (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`")"
write-host -ForegroundColor red $message
NewEventSource 
write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1003 -Message $message -EntryType Error 
exit 1 
}




# Get Computers that have $FirstProperty value as: $FirstPropVal 
try
{
$TargetComp = $Class | Get-SCOMClassInstance | Where-Object {
$_."[$($Class.Name)].$FirstProperty".value -match $FirstPropVal -OR $_.$FirstProperty -match $FirstPropVal`               ##-- DIFFERENT COMBINATION (THE "[$($Class.Name)]" SYNTAX IS TO INCLUDE CASE OF A NOTE PROPERTY
#-AND $_."[$($Class.Name)].$SecondProperty".value -eq $SecondPropVal -OR $_.$SecondProperty -eq $SecondPropVal`     ##-- ADDITIONAL POTENTIAL PROPERTIES (SEE SCRIPT PARAMS)
} -ErrorAction Stop

#$TargetComp = $Class | Get-SCOMClassInstance | Where-Object {                                                       ## -- TO TEST UNFOUND COMPUTER SCENARIO
#$_."[$($Class.Name)].$FirstProperty".value -eq "azerty" -OR $_.$FirstProperty -eq "azerty"`                        ## -- TO TEST UNFOUND COMPUTER SCENARIO
#} -ErrorAction Stop                                                                                                ## -- TO TEST UNFOUND COMPUTER SCENARIO

}
catch
{
$message = "ERROR DURING RETRIEVE OF CLASS INSTANCES (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`")"
write-host -ForegroundColor red $message
NewEventSource 
write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1004 -Message $message -EntryType Error 
exit 1 
}




switch($Action)
{
"Delete" {


# Analyse the content of $TargetComp
switch($TargetComp.Count)
{
{$_ -lt 1}                  {            
                            $message = "NO AGENT TO REMOVE (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`")"
                            Write-Host -F Blue -B White $message
                            NewEventSource 
                            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1005 -Message $message -EntryType Information 
                            }


{$_ -ge 1 -AND $_ -le $ThreshNotDelete} ## -- SECURITY OPTION TO AVOID DELETION OF TWO MANY AGENTS. BE SURE OF THE APPLIED CRITERIAS BEFORE UNLOCK THAT!
                            {
                            $message = "FOLLOWING AGENTS WILL BE REMOVED:"
                            Write-Host -F Yellow $message
                            $TargetComp.displayname
                                                            
                                DeleteSCOMAgent -AgentComputerName $TargetComp.displayname -MSServer $MS
                                #$result
                                switch($result)
                                    {
                                    "Agents deleted" 
                                                                                        {
                                                                                            $message = "FOLLOWING AGENTS HAS BEEN REMOVED FROM SCOM CONSOLE (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`") :`n "
                                                                                            $message += $TargetComp | foreach {$_.DisplayName ;"`n"}
                                                                                            write-host $message
                                                                                            NewEventSource 
                                                                                            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1006 -Message $message -EntryType Information 
                                                                                        }
                                    
                                    "Error during deletion of one ore more agent" 
                                                                                        {
                                                                                            $message = "ERROR DURING DELETION OF ONE OR MORE AGENT! MANUAL CHECK REQUIRED (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`") "
                                                                                            write-host $message
                                                                                            NewEventSource 
                                                                                            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1007 -Message $message -EntryType Warning
                                                                                        } 

                                    "No Agent found to delete" 
                                                                                        {
                                                                                            $message = "NO AGENT FOUND TO DELETE - MANUAL CHECK REQUIRED (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`")"
                                                                                            write-host $message
                                                                                            NewEventSource 
                                                                                            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1008 -Message $message -EntryType Warning
                                                                                        } 


                                    
                                
                                    
                                
                            
                                }

                            }

{$_ -gt $ThreshNotDelete}                 {
                            $message = "WARNING: NUMBER OF AGENTS TO REMOVE IS GREATER THAN 10 ! MANUAL CHECK REQUIRED"  ## -- SECURITY OPTION TO AVOID DELETION OF TWO MANY AGENTS. BE SURE OF THE APPLIED CRITERIAS BEFORE UNLOCK THAT!
                            Write-Host -F red $message
                            $TargetComp.displayname
                            NewEventSource 
                            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1009 -Message $message -EntryType Warning
                            }


}


         }


"Maintenance" {

#Clear-Variable message

    If ($TargetComp.Count -ge 1)
        {

        foreach ($target in $TargetComp)
            {
            If (Get-SCOMMaintenanceMode -Instance $target)
                {
                #$message += "`n$target IS ALREADY IN MAINTENANCE MODE"
                $AlreadyInMM += "$target`n"
                }
            Else
                {
                SetMM -HostToMM $target -Duration $MaintenanceDuration
                $PutInMM += "$target`n" 
                }
            }
                       

            $message = "`nFOLLOWING AGENTS HAS BEEN SET IN MAINTENANCE MODE (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`") :`n"
            $message += $PutInMM
            $message += "`n`nFOLLOWING AGENTS ARE ALREADY IN MAINTENANCE MODE (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`") :`n"
            $message += $AlreadyInMM
            write-host $message
            NewEventSource 
            write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1010 -Message $message -EntryType Information 
         }
        
    Else
        {
        $message = "NO AGENT TO PUT IN MAINTENANCE MODE HAS BEEN FOUND. (CRITERIAS: Class=`"$ObjectClass`" - Property=`"$FirstProperty`" - Value=`"$FirstPropVal`")"
        write-host $message
        NewEventSource 
        write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1011 -Message $message -EntryType Information
        }
    }


default {

        $message = "No action has been choosed. Possible value: `"Delete`" (Delete Agent from console) or `"Maintenance`" (Put corresponding computer in Maintenance Mode)"
        write-host -ForegroundColor red $message
        NewEventSource 
        write-eventlog -logname "Operations Manager" -Source $ScriptName -EventID 1012 -Message $message -EntryType Error 
        exit 1 
        }

}

 

SCOM - Script - Comparaison Agents et Liste Machines

Le script ci-dessous propose de comparer un extract des agents scom avec une liste de machine, pour un suivi de déploiement par exemple.

Compare_SCOMAgent_ComputerList.ps1 (1,67 kb)

 

### COMPARE SCOM AGENTS AND COMPUTER LIST IN TXT FILE

#Parameters
Param(
[Parameter(Mandatory=$false)]
$MS="MyMS.MyDomain",
[Parameter(Mandatory=$false)]
$Cred = $(Get-Credential "MyDomain\Me"),
[Parameter(Mandatory=$false)]
$FilePath = "C:\ServerList.txt "
)


#Import du module SCOM
try
{
Import-Module -Name OperationsManager -ErrorAction stop
}
catch
{
write-host -ForegroundColor red "Erreur lors de l'import du module SCOM"
}

#Connection au management group $MGroup
New-SCOMManagementGroupConnection -ComputerName $MS -Credential $Cred


# Recuperation de la liste des agents (netbios name
$agents = Get-SCOMAgent | select computername -ExpandProperty computername


# Import du fichier $FilePath
try
{
$ComputerList = Get-Content -Path $FilePath
}
catch
{
write-host -ForegroundColor red "Error during import of `"$FilePath`""
}




# Machines dans Scom ET dans la liste
$Both = $(Compare-Object -ReferenceObject $agents -DifferenceObject $ComputerList -IncludeEqual -ExcludeDifferent).inputobject

# Machines uniquement dans SCOM
$InScom = $(Compare-Object -ReferenceObject $agents -DifferenceObject $ComputerList | Where-Object {$_.sideindicator -eq "<="}).inputobject

# Machines uniquement dans la liste
$InFile = $(Compare-Object -ReferenceObject $agents -DifferenceObject $ComputerList | Where-Object {$_.sideindicator -eq "=>"}).inputobject




write-host -B White -F Blue "`n $($both.Count) COMPUTERS THAT ARE IN SCOM AND IN FILE:"
$Both

write-host -B White -F Blue "`n $($InScom.Count) COMPUTERS THAT ARE ONLY IN SCOM:"
$InScom

write-host -B White -F Blue "`n $($InList.Count) COMPUTERS THAT ARE ONLY IN FILE:"
$InFile



 

Office 365 : Voir qui a réservé la salle de réunion

Aujourd'hui lorsque l'on utilise Exchange Online et les boites aux lettre de salle, la configuration par défaut du calendrier de ces boites ne permet de voir que le statut de celle-ci soit "Libre ou Occupée" en revanche il n'est pas possible de voir qui a réservé la salle.

C'est parce que par défaut les droits sur le calendrier sont en "AvailabilityOnly", comme le montre la capture ci dessous.

 

 

A l'aide de Powershell, il est possible de modifier les droits sur le calendrier pour afficher qui est la personne ayant fait la réservation, pour ce faire voici les cmdlets.

#Construction de la session Exchange Online
$cred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $Cred -Authentication Basic -AllowRedirection

# Import de la session
Import-PSSession $Session

# Audit des droits
Get-MailboxFolderPermission -Identity Nom_de_la_Salle_de_réunion:\calendar

# Modification des droits
Set-MailboxFolderPermission -Identity Nom_de_la_Salle_de_réunion:\calendar -User default -AccessRights LimitedDetails

 

Maintenant il est possible de voir le statut de la salle de réunion ainsi que les personnes l'ayant réservé.

Azure Stack : Bug lors de la connexion PEP

Dans Azure Stack, l’établissement d’une connexion au PEP (Privileged EndPoint), appelé également VM ERC (Emergency Recovery Console), est nécessaire pour mener certaines opérations de test de l’environnement (Test-AzureStack préalable à une mise à jour) ou pour déployer certaines ressources (Resource Providers…).

La mise à jour 1910 d’Azure Stack introduit deux nouveaux cmdlet Powershell accessibles depuis le PEP : Get et Set-AzsDnsForwarder.

Malheureusement, il semble que ce module n’apprécie pas beaucoup d’être chargé depuis un ordinateur exécutant un système non-anglais puisque l’ouverture de la sessions PEP ne fonctionne plus non plus depuis cette mise à jour, avec un message d’erreur laissant entendre l’impossibilité d’ouvrir la version francaise du module AzureStack DNS :

clip_image002

Cannot find the Windows Powershell data file « Microsoft.AzureStack.DNS.psd1 » in directory « C:\Program Files\WindowsPowerShell\Modules\Microsoft.AzureStack.DNS\fr-FR », or in any parent culture directories

Les VM ERC sont assez lourdement verrouillées, et il est impossible d’aller corriger l’installation de ce module.

Il est par contre possible de forcer une Culture différente lors de l’ouverture de la Remote-PSSession à l’aide du paramètre SessionOption :

New-PSSession -ComputerName $IP -ConfigurationName PrivilegedEndpoint -Credential $AzureCredential -SessionOption (New-PSSessionOption -UICulture en-US)

Voilà qui devrait suffire à contourner le problème en attendant que Microsoft apporte une correction plus définitive !

Azure Stack : Remplacement des certificats App Service

Le Resource Provider App Service d’Azure Stack nécessite l’utilisation de certificats, qui devront donc être remplacés avant d’arriver à expiration ou en cas de compromission. Notez d’ailleurs qu’aucune alerte n’est présente dans le portail pour prévenir de leur expiration…

Bien que cette opération doive par définition être effectuée assez régulièrement, elle n’est curieusement pas documentée sur Technet.

Heureusement, elle est très simple !

Ouvrez la blade App Service dans le portail d’administration, puis dans le menu Secrets, cliquez sur Rotate dans la partie Certificates :

clip_image002

Sélectionnez ensuite les fichiers .pfx des certificats renouvelés et entrez leurs mots de passe :

clip_image004

Une fois tous les champs remplis, cliquez sur OK.

La procédure de rotation débute alors. Il est possible de suivre sa progression en cliquant sur le bouton Status :

clip_image005 clip_image007

Après environ 20 minutes, la procédure est terminée :

clip_image009

A noter : aucune interruption de service n’a été constatée pendant le déroulement de la rotation du certificat (avec un Resource Provider déployé en haute disponibilité)

Azure Stack : Le Resource Provider App Service ne se charge plus

Quelques temps après avoir déployé le Resource Provider App Service dans notre environnement Azure Stack, j’ai eu la mauvaise surprise de constater qu’il ne se chargeait plus et qu’il n’était plus possible de créer de nouvelles Web App :

clip_image002

Could not validate app name

Ni d'accéder aux propriétés de celles déjà créées :

clip_image004

La console de debug du navigateur (touche F12) permet d’observer un grand nombre d'erreurs 500 pour des requêtes vers https://management.<location>.<domaine> et vers https://api.appservice.<location>.<domaine> :

clip_image005

Dans le portail d’administration, le dashboard app service ne se charge plus non plus, et le message d’erreur donne un premier indice sur la cause du dysfonctionnement :

clip_image007

Failed to load App Service extension. Please check whether App Service resource provider and database is up and running

Allons donc voir du côté des VM « contrôleur » (CN0 et CN1) de l’environnement du Resource Provider. Il y est possible de s’y connecter en RDP à condition d’autoriser le port 3389 dans leur NSG.

Ces VM contiennent une console MMC Web Cloud Management (son raccourci se trouve sur le bureau) qui permet la gestion de tous les composants du RP (Front End, Workers…) et pourrait donc nous en apprendre plus, mais elle plante lors de son ouverture :

clip_image009

The Resource Metering Service has experienced an unhandled exception. Exception: 'Microsoft.Web.Hosting.WebHostingException: Login failed for user 'appservice_metering_Common'. ---> System.Data.SqlClient.SqlException: Login failed for user 'appservice_metering_Common'.)

Ce nouveau message d’erreur sembler confirmer un problème du côté de la base de données.

Cette dernière est hébergée sur un cluster Always On qui fait partie de l’environnement « backend » du Resource Provider : il a été déployé séparément, en utilisant le template « haute disponiblité » de référence Microsoft.

Il est possible de se connecter en RDP à un des nœud du cluster (aps-sql-0 ou 1) à partir d’une des VM « contrôleur » CN-VM sans modifier les règles NSG, à l’aide du compte admin du domaine utilisé pour déployer l’environnement backend.

Une fois connecté, on peut ouvrir SQL Management Studio sur les deux instances :

clip_image010

On constate alors qu'une seule des instance dispose des bases de données nécessaires au fonctionnement du Resource Provider.

La raison en est simple : c'est parce que le template de déploiement du backend fourni par Microsoft ne configure pas automatiquement l'availability group always on. C'est d'ailleurs rappelé dans les release notes du Resource provider, il faut le configurer manuellement… mais il est facile de manquer ce détail, et la procédure n’est pas détaillée.

Commençons donc par sauvegarder les bases, puis identifions le serveur qui est configuré comme « Primary » dans l’Availability Group Always On :

clip_image011

La procédure d’ajout des bases ne peut être réalisée que sur le nœud « primary », mais il doit aussi être celui qui possède les bases; ce n’est pas le cas ici (les bases sont sur le nœud « secondary », il faut donc commencer par réaliser un failover de l'availability group.

Nous pouvons ensuite y rajouter les bases :

Faites un clic-droit sur Availability Databases puis sélectionnez Add Database.

Cochez les bases à ajouter :

clip_image013

Cliquez sur connect pour ouvrir la connexion vers l'autre noeud

clip_image015

Sélectionnez une synchronisation « Full » puis terminez l’assistant.

Les bases sont très petites et la synchronisation est donc quasi-instantanée.

Une fois terminée, la MMC Web Cloud doit maintenant se lancer sans erreur et le Resource Provider est à nouveau fonctionnel!

O365 : Bug de Synchro après un Hard match

L'utilisateur apparait comme un compte cloud

Après un Hard link, il est normal que le compte reste affiché comme un compte cloud dans O365, même si le compte O365 est bien rattaché au compte Active Directory, ce dernier ne change pas d'état. 

Afin de corriger cela il vous suffit de faire une modification sur l'un des attributs du compte pour qu'il soit de nouveau synchronisé avec AD Connect et enfin réapparaître comme un objet synchronisé avec Active Directory.

O365 : Modification de l'UPN

Dans certain cas de figure (mariage, divorce...) les utilisateurs de l'AD change de nom, ceux qui a pour impact un renommage du compte Active Directory, jusque la pas de problème mais (parce qu'il en faut un) lorsque vous utilisez "AD Connect" pour synchroniser vos utilisateurs locaux (votre Active Directory) avec Office 365 (Azure Active Directory), certains paramètres ne sont pas synchronisés.

Parmi ces paramètres le UserPrincipalName, plus communément appelé UPN ne peut être modifié depuis l'AD et répliqué vers O365.

Pour modifier l'UPN côté O365 vous devrez utiliser la commande Powershell suivante:

Set-MsolUserPrincipalName -UserPrincipalName AncienUPN@mondomaine.com -NewUserPrincipalName NouvelUPN@mondomaine.com