PI Services

Le blog des collaborateurs de PI Services

PowerShell - Les bienfaits du splatting

Ça pique les yeux

 

Vous avez peut être déjà eu recours à la commande (cmdlet) suivante pour créér un compte dans l'Active Directory (AD) :

New-ADUser -Name $Name -samAccountName $samAccountName -userPrincipalName $UserPrincipalName -Path $Path -AccountPassword $AccountPassword -DisplayName $DisplayName -GivenName $GivenName -sn $sn -Description $Description -Server $Server -ChangePasswordAtLogon -Enabled

 

Oui ca fait mal aux yeux, mais pourquoi ne pas utiliser le caractère backtick ` qui permet de scinder une cmdlet sur plusieurs lignes ?

New-ADUser -Name $Name -samAccountName $samAccountName 
` -userPrincipalName $UserPrincipalName
` -Path $Path -AccountPassword $AccountPassword 
` -DisplayName $DisplayName -GivenName $GivenName -sn $sn
` -Description $Description -Server $Server
` -ChangePasswordAtLogon -Enabled

 

Effectivement, c'est mieux, mais cela n'est toujours pas très esthétique, peut-on faire encore mieux ?

 

Le splatting

 

Le splatting permet de passer à une cmdlet un hash table (tableau associatif), array (tableau) ou une liste d'arguments qui va contenir la liste des paramètres voulus

$parameters = @{ #Ceci est un hash table qui va associer à gauche du signe égal le nom du paramètre avec à droite la valeur du dit paramètre
    Name = $Name
    samAccountName = $samAccountName
    userPrincipalName = $userPrincipalName
    Path = $Path 
    AccountPassword = $AccountPassword 
    DisplayName = $DisplayName
    GivenName = $GivenName
    sn = $sn
    Description = $Description
    Server = $Server
    ChangePasswordAtLogon = $true
    Enabled = $true
}

New-ADUser @parameters #Pour utiliser le splatting il faut passer en paramètre le hash table à l'aide du caractère @ et non $

 

En plus de rendre le code plus lisible, les méthodes associées aux hash table sont désormais accessibles, si par exemple on veut ajouter ou retirer des éléments plus loin dans le code :

 

$parameters.add('employeeID', $EmployeeID) #Ajout du paramètre à gauche du signe , employeeID et à droite la valeur du dit paramètre dans le hashtable $parameters 
$parameters.remove('ChangePasswordAtLogon') #Suppression du paramètre ChangePasswordAtLogon du hash table $parameters

 

Pour aller plus loin

 

Documentation officielle de Microsoft sur le splatting

Azure PowerShell - Forcer la connexion à Azure lorsque le réseau est instable

Un peu de contexte

 

Dans certains environnements la connexion réseau vers Internet et notamment vers Azure peut présenter des défaillances.

Lorsque qu'un administrateur se connecte de façon interactive en PowerShell à Azure, un simple échec importe peu et une nouvelle tentative est souvent fructueuse, lorsque c'est une tâche automatisée qui est exécutée c'est une autre histoire, toutes les actions qui dépendent de cette connexion échouerons si la connexion vers Azure AD est un échec.


Le code

$i = 0 #Variable qui sera incrémentée à chaque nouvelle tentative de connexion à Azure
$ConnectAzureAD = "Fail" #Variable qui permet de sortir de la boucle si une tentative de connexion vers Azure AD est réussite
do #Do until permet d'exécuter un script en boucle tant qu'une condition n'est pas atteinte
{
    try #Try catch permet de choisir comment les erreurs de cmdlet seront gérés, ici on s'en sert pour attendre avant la prochaine tentative de connexion et potentiellement faire du logging
    {
        $i++ #Permet d'incrémenter la variable $i
        Connect-AzureAD #Cmdlet qui permet de se connecter à Azure AD, dans un script automatisé, les identifiants d'un compte de service seront utilisé à l'aide du paramètre -Credential $Credentials (objet PSCredential à créer)
        $ConnectAzureAD = "Success" #La connexion à Azure AD est un succès puisque nous sommes dans le try, on peut donc modifier la variable $ConnectAzureAD pour pouvoir sortir de la boucle, code qui fonctionne de paire avec la condition dans le until 
        #Il est recommandé de consacrer une ligne pour faire du logging
    }

    catch 
    {
        #A nouveau il est recommandé de consacrer une ligne pour faire du logging
        Start-Sleep 10 #Permet de faire une pause de 10 secondes avant la nouvelle tentative de connexion
    }
}
until ($ConnectAzureAD -eq "Success" -or $i -eq 6) #Si une connexion vers Azure AD est réussie ou si 6 tentatives infructueuses ont été observées, le script arrêtera d'essayer de se connecter à Azure AD

 

 

En résumé, le script tentera de se connecter à Azure AD en powershell jusqu'à ce qu'une connexion soit établie ou que 6 tentatives de connexions aient échouées.

Powershell : Trouver la date de dernière connexion d'un utilisateur.

Comme vous le savez l'un des attributs qui nous est le plus important pour déterminer l'inactivité d'un compte est l'attribut "LastLogon", ce dernier permet de connaitre la dernière authentification valide d'un compte Active Directory.

Le problème c'est que ce dernier n'est pas répliqué entre les DCs, attention je parle bien du "LastLogon" et non le "LastLogonTimeStamp" qui lui l'est mais, ne détient pas la valeur réelle de la dernière authentification réussie.

Le "LastLogon" n'est pas répliqué entre les DCs pour une raison simple, éviter les "tempêtes" de réplication entre les DCs, imaginez, à chaque ouverture / déverrouillage de session cette valeur change, si vous pensez au nombre de fois que sont déverrouillées des sessions à la journée, cela vous donne une idée des réplications qui seraient nécessaires, par conséquent cet attribut n'est pas répliqué.

Ce qui pose donc problème c'est qu'il n'est pas possible d'avoir la réelle valeur de "LastLogon" sans devoir interroger l'intégralité des DCs et faire une comparaison de cette dernière.

Voici un script qui fera les requêtes et comparaisons pour vous, toutefois gardez à l'esprit qu'il va pour chaque utilisateur demander la valeur de l'ttribut "LastLogonà chaque DC, par conséquent ce script peut prendre plus ou moins de temps à s'exécuter en fonction du nombre d'utilisateur et du nombre de DCs.

$Array = @()
$AllDC = Get-ADDomainController -Filter * | sort Name | select Name
$AllEnabledUsers = Get-ADUser -Filter {Enabled -eq $true} | select Samaccountname

$AllEnabledUsers | select -First 5 | foreach {
    $CurrentUser = $_.Samaccountname
    $RealLastLogon = $null

    $AllDC | foreach {
        $CurrentDC = $_.Name

        Try {
            $Logon = Get-ADUser $CurrentUser -Properties LastLogon -Server $CurrentDC
            $LastLogon = [Datetime]::FromFileTime($Logon.LastLogon)
            If ($LastLogon -gt $RealLastLogon) {
                $RealLastLogon = $LastLogon
                }

            # Release variable
            $LastLogon = $null
            }
        Catch {
            Write-Warning $($_)
            }

        # Release variable
        $CurrentDC = $null
        }
    
    # Store Data
    $Array += New-Object psobject -Property @{
        DistinguishedName = $Logon.DistinguishedName
        Enabled = $Logon.Enabled
        GivenName = $Logon.GivenName
        Name = $Logon.Name
        ObjectClass = $Logon.ObjectClass
        ObjectGUID = $Logon.ObjectGUID
        SamAccountName = $Logon.SamAccountName
        SID = $Logon.SID
        Surname = $Logon.Surname
        UserPrincipalName = $Logon.UserPrincipalName
        LastLogon = $RealLastLogon
        }
        
    # Release Variables
    $CurrentUser = $null
    $RealLastLogon = $null
    }

Il ne vous restera qu'a examiner la sortie en rappelant la variable "$Array" ou à l'exporter dans un CSV comme ci-dessous par exemple.

$Array | Export-Csv C:\Temp\AllUsersWithLastLogon.csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation

 

Si la valeur "LastLogon" est égale à "01/01/1601 01:00:00" cela veut dire que le compte ne s'est jamais connecté

Script - API Vmware VCenter - Get VM infos

Le script ci-dessous est un exemple simple de l'utilisation de l'API Rest de Vcenter pour recuperer toute sorte d'information, nottament sur les machines virtuelles.

A noter que la limitation du nombre d'objet retournés oblige simplement a recuperer dans un premier temps la liste des hosts, puis par host la liste des VMs.

 

### QUERY VCENTER REST API TO GET VM LIST ###


$user = ‘myaccount’
$pswd = Read-Host -Prompt "Enter Password"
$vCenterName = ‘MyVcenter’
$encoded = [System.Text.Encoding]::UTF8.GetBytes(($user, $pswd -Join ‘:’))
$encodedPassword = [System.Convert]::ToBase64String($Encoded)
$authHeader = @{
Authorization = "Basic $($EncodedPassword)"
}
$sRest = @{
Method = ‘Post’
Uri = "https://$($vCenterName)/rest/com/vmware/cis/session"
Headers = $authHeader
}
$result = Invoke-RestMethod @sRest


# Get TokenID
$authHeader = @{
‘vmware-api-session-id’ = $result.value
}


# Get All Hosts
$gethosts = "https://$($vCenterName)/rest/vcenter/host"
$resultgethost = Invoke-RestMethod -Uri $gethosts -Headers $authHeader
$hostidlist = $resultgethost.value.host


# For each host, get all VMs

foreach ($hostid in $hostidlist)
{
$get_vm = "https://$($vCenterName)/rest/vcenter/vm?filter.hosts=$hostid"
$resultvm = Invoke-RestMethod -Uri $get_vm -Headers $authHeader
[array]$FinalTableau += $resultvm
}

# Display Result
$FinalTableau.value | select name,power_state


# Output to CSV
$CsvTab = $FinalTableau.value | select name,power_state | ConvertTo-Csv -Delimiter ';' -NoTypeInformation
$CsvTab | Out-File .\VMList.csv

 

 

 

 

Powershell : Comparer une date manuellement saisie avec un format spécifique à la date du last logon d'un utilisateur dans Active Directory

Dans le cadre de l'automatisation, il arrive de recevoir une demande pour développer un script PowerShell pour le nettoyage ou la gestion de l'obsolescence des utilisateurs dans l'Active Directory.

Dans le script, vous aurez peut être besoin de comparer la date du last logon utilisateur dans l'Active Directory avec une date manuellement saisie (variable du script) avec un format spécifique.

Ci-dessous un exemple de PowerShell pour comparer une date donnée avec une date de last logon utilisateur dans Active Directory :

# Import Active Directory Module
Import-Module ActiveDirectory
 
#Set a fixed date for comparison
$Fixed_Date = "13/11/2021"
 
#Convert the fixed date from a string to a compatible specific format
$Fixed_Date_Convert = [datetime]::parseexact($Fixed_Date, 'dd/MM/yyyy', $null)  
 
#Get AD user last logon date in dd/MM/yyyy format
$ADUser = get-aduser "jdoe" -Properties lastlogondate | select @{Name=”ModifiedLastLogonDate”;Expression={$_.LastLogonDate.ToString(“dd/MM/yyyy”)}}
 
#Convert AD last logon date to a specific format to be compared with the chosen date above
$ADdate = [datetime]::parseexact($ADUser.ModifiedLastLogonDate, 'dd/MM/yyyy', $null)
 
if($ADdate -le $Fixed_Date_Convert)
    {
        echo "Active directory last logon date is inferior to the fixed date"
        }
    else
    {
        echo "Active directory last logon date is superior to the fixed date"
        }

Conclusion:

La méthode [datetime]::parseexact(dateString, format, provider) Convertit la représentation sous forme de chaîne spécifiée d'une date et d'une heure en son équivalent DateTime.

Script - Invoquer un update d'un agent Trend OSC a distance

Le script ci-dessous propose d'utiliser a distance la commande "PccNTMon.exe -u" sur un agent Trend OSC pour invoquer une mise a jour, en direction de son serveur OSC de rattachement.

 

#### RemoteInvokeTrendOSCAgentUpdate.ps1: REMOTELY INITIATE AN UPDATE OF A TREND OSC AGENT ####

## COMMENT: The script execute command through PSSession and open a RDP window to allow interactive use of "OSCAgentExe -u" ###

param(
# Target Computer
$Computer = "MyTarget",
# Cred
$Cred = $(Get-Credential -Credential "MyAccount"),
# OSC Agent Folder
$OSCAgentFolder = "C:\Program Files (x86)\Trend Micro\OfficeScan Client\",
# OSC Client Process
$OSCClientProc = "PccNTMon"
)


# OSC Agent Exe
$OSCAgentExe = "$OSCAgentFolder$OSCClientProc`.exe"


# FUNCTIONS
function Set-WindowState {
	
	[CmdletBinding(DefaultParameterSetName = 'InputObject')]
	param(
		[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
		[Object[]] $InputObject,

		[Parameter(Position = 1)]
		[ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE',
					 'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED',
					 'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
		[string] $State = 'SHOW'
	)

	Begin {
		$WindowStates = @{
			'FORCEMINIMIZE'		= 11
			'HIDE'				= 0
			'MAXIMIZE'			= 3
			'MINIMIZE'			= 6
			'RESTORE'			= 9
			'SHOW'				= 5
			'SHOWDEFAULT'		= 10
			'SHOWMAXIMIZED'		= 3
			'SHOWMINIMIZED'		= 2
			'SHOWMINNOACTIVE'	= 7
			'SHOWNA'			= 8
			'SHOWNOACTIVATE'	= 4
			'SHOWNORMAL'		= 1
		}

		$Win32ShowWindowAsync = Add-Type -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
'@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru

		if (!$global:MainWindowHandles) {
			$global:MainWindowHandles = @{ }
		}
	}

	Process {
		foreach ($process in $InputObject) {
			if ($process.MainWindowHandle -eq 0) {
				if ($global:MainWindowHandles.ContainsKey($process.Id)) {
					$handle = $global:MainWindowHandles[$process.Id]
				} else {
					Write-Error "Main Window handle is '0'"
					continue
				}
			} else {
				$global:handle = $process.MainWindowHandle
			}

			$Win32ShowWindowAsync::ShowWindowAsync($handle, $WindowStates[$State]) | Out-Null
			Write-Verbose ("Set Window State '{1} on '{0}'" -f $handle, $State)
		}
	}
}




# FOR EACH COMPUTER
foreach ($Comp in $Computer) {


# Create PSSession
try
{
New-PSSession -ComputerName $Comp -Credential $Cred -Name "PSSession_$Comp" -ErrorAction Stop
}
catch
{
write-host -F Red "Error during New-PSSession `n $($Error[0].Exception)"
exit 1 
}


# Get PSsession
$RemoteSession = Get-PSSession -Name "PSSession_$Comp"


# Open RDP Session (needed because the invoke update is interactive)
cmdkey /generic:TERMSRV/$Comp /user:($Cred.UserName) /pass:($Cred.GetNetworkCredential().Password)

mstsc /v:$Comp /w:50 /h:50

Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10


# Get the RDP process Id to kill it at the end
$ProcId = (Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}).Id


# Minimize RDP Window
(Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}) | foreach {Set-WindowState $_ HIDE}


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Invoke Update
write-host "Invoking update..."
Invoke-Command -Session $RemoteSession -ScriptBlock {Start-Process -FilePath $Using:OSCAgentExe -ArgumentList "-u"} 


        # Wait while update (see for update of ofcscan.ini file)
        do {
            Write-Host "Wait while update..."
           }

        until

           (
            (Invoke-Command -Session $RemoteSession -ScriptBlock {Get-ChildItem -Path "$Using:OSCAgentFolder`ofcscan.ini" | Where-Object {$_.LastWriteTime -gt $(get-date).AddMinutes(-15)}})
           )


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Close RDP Session
write-host "Logoff RDP Session on $Comp..."
Invoke-Command -Session $RemoteSession -ScriptBlock {`
    $CredUser = $($Using:Cred.UserName)
    $sessions = quser | Where-Object {$_ -match $CredUser} ; 
    $sessionIds = ($sessions -split ' +')[2] ; 
    Write-Host "Found $(@($sessionIds).Count) user login(s) on computer.";
    $sessionIds | ForEach-Object {Write-Host "Logging off session id [$($_)]..." ; logoff $_}
     
     }


# Close RDP Session Disconnect Window by killing process
Get-Process -Id $ProcId | stop-process


}

# Remove Pssession
Get-PSSession | Remove-PSSession

 

Powershell : Supprimer les KB "Declined"

Quand on veut faire du ménage sur son WSUS et également dans la base de ce dernier, il peut s'avérer utile de supprimer les KB dont le statut est "IsDeclied".

Pour réaliser cela rien de plus simple que quelques lignes de Powershell et de la patience (beaucoup de patience si ça fait longtemps que cela n'a pas été fait).

Connexion

# Define Server Name
$WsusServer = "Mon-Server-WSUS"
# Define connection port
$WsusPort = "8530"

# Initiate Connection
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)

# Verifying connection (Should be return the name of the wsus server)
$Wsus.name

 

Définition des Updates à supprimer

# List All Kb in WSUS database
$AllKb = $Wsus.GetUpdates()

# Filter on "IsDeclined" status
$IsDeclined = $AllKb.Where({$_.IsDeclined -eq $True})

 

Suppression des KB

# Delete KB
$IsDeclined | foreach {
    # Define Current Id
    $Id = $_.Id
    Try {
        $Wsus.DeleteUpdate($Id.UpdateId.ToString())
        }
    Catch {
        Write-Warning $($_)
        }
    # Release variable
    $Id = $null
    }

Cette commande est un peu longue mais si elle est exécutée régulièrement, la purge dure moins longtemps.

Powershell : Change the owner of my AD objects

Comme évoqué dans l'article  "Powershell : Who's the owner of my AD objects", il est possible que votre AD contienne des objets dont le propriétaire ne soit aucun des suivants :

  • "Enterprise Admins"
  • "Domain Admins"
  • "Administrators"

Afin de remettre "Domain Admins" comme propriétaire des objets, nous utiliserons Powershell pour chacun des types d'objets.

Attention : La variable $NoGood est issue des scripts du précédent article, pensez à vérifier ce qu'elle retourne au préalable.

Unités d'organisation

# Organizational Units
$NoGood | foreach {
    # Current OU
    $DistinguishedName = $_.DistinguishedName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADOrganizationalUnit -Identity $DistinguishedName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
         Write-Warning $($_)
         $DistinguishedName
        }

    # Release variable
    $DistinguishedName = $null
    }

Les groupes

# Group
$NoGood | foreach {
    # Current Group
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADGroup $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }
    
    # Release variable
    $SamAccountName = $null
    }

Les utilisateurs

# Users
$NoGood | foreach {
    # Current User
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADUser $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }
    
    # Release variable
    $SamAccountName = $null
    }

 

Les ordinateurs

# Computers
$NoGood | foreach {
    # Current  Computer
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADComputer $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }

    # Release variable
    $SamAccountName = $null
    }

 

O365 : Forcer le changement de mot de passe

Il arrive dans certain cas de figure que nous souhaitions forcer le changement de mot de passe des comptes O365.

S'il s'agit d'un seul utilisateur voici la commande :

Set-MsolUserPassword -UserPrincipalName jdupont@mondomaine.com -ForceChangePasswordOnly $true -ForceChangePassword $true

Prenez soin de modifier le Userprincipalname de la commande sous peine d'obtenir une erreur.

 

En revanche si l'on veut forcer l'intégralité de la société à changer de mot de passe cela va nécessiter quelques lignes de plus.

# Variables
$LogFolder = "C:\temp"
$LogFile = "$LogFolder\LogO365_Reset.txt"
$LogFileError = "$LogFolder\LogO365_Reset_Error.txt"

# check
If (!(Test-Path $LogFolder)) {
    New-Item $LogFolder -ItemType Directory
    }

# Exceptions
$FilteredUsers = "Userprincipalname1", "Userprincipalname2", "Userprincipalname3" # Ajouter les UPN à ne pas reset (exemple  le compte Admin du Tenant)

# Connect to O365
Connect-MsolService

# Get users
$AllUsers = Get-MsolUser -MaxResults 10000 | select UserPrincipalName

# Force to change Password
$AllUsers | foreach {
    $UPN = $_.UserPrincipalName
    If ($FilteredUsers -eq $UPN) {
        Write-Host "Do not reset Password For $UPN because we had filtered him" | Add-Content $LogFile
        }
    Else {
        Try {
            Set-MsolUserPassword -UserPrincipalName $UPN -ForceChangePasswordOnly $true -ForceChangePassword $true
            Write-Output "Succesfully reset Password For $UPN" | Add-Content $LogFile
            }
        Catch {
            $Date = Get-Date
            Write-Warning "At $Date the following Error Appear $($_)" | Add-Content $LogFileError
            }
        }
    }

 

Bon courage au service IT pour le nombre d'appel qu'il va recevoir. 

 

O365 : Réaliser un hard match

 

Comme expliqué dans l'article précédent "O365 : Soft Match (SMTP) et Hard Match (ImmutableID)" le Hard Match intervient lorsque le Soft Match n'a pas fonctionné.

Les étapes à suivre sont les suivantes:

  1. Récupérer le GUID du compte dans l'Active Direcotry
  2. Convertir ce dernier en ImmutableID
  3. Appliqué cet ImmutableID au compte Azure Active Directory
  4. Relancer une synchronisation via Ad connect 

Voici donc les commandes pour cela.

# Get GUID for User
$User = Get-ADUser jdupont | select ObjectGUID,UserPrincipalName
$Upn = $User.UserPrincipalName
$Guid = $User.ObjectGUID.Guid

# Convert GUID to ImmutableID
$ImmutableId = [System.Convert]::ToBase64String(([GUID]($User.ObjectGUID)).tobytearray())

# Connect MsolService
Connect-Msolservice

# Set ImmutableID to msoluser
Set-MsolUser -UserPrincipalName $Upn -ImmutableId $ImmutableId

 

Et voila, vous n'avez plus qu'a relancer une Synchor AD Connect via la commande suivante.

Start-ADSyncSyncCycle -PolicyType Delta