Accéder au contenu principal

Office 365 : Script PowerShell pour créer le mapping des utilisateurs dans ShareGate à partir de SharePoint 2007

 Lors du travail de préparation à la migration des sites SharePoint On Premise vers Office 365 SharePoint Online, il y a plusieurs étapes à mener telles que:

Une fois ce travail effectué, le client de migration ShareGate vous permet de faire un mapping pour chaque utilisateur entre le monde NTLM On Premise et le monde Office 365 et Azure AD.

Pour ceci, l’option la plus simple reste le client lui même avec un module de recherche simple:

image

En revanche dès que le nombre d’utilisateurs est important, il devient impossible de faire ce type de mapping manuel. Le module d’import XML est la solution en respectant le format suivant:

<?xml version="1.0"?>
<UserAndGroupMappings xmlns:xsd="
http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Mappings>
    <Mapping>
      <Source AccountName="DOMAIN\xxxxx_yyyyyy1" DisplayName="Xxxxx Yyyyyy 1" PrincipalType="User" /> 
      <Destination AccountName="i:0#.f|membership|xxxxx.yyyyyy1@mydomain.com" DisplayName="Xxxxx Yyyyyy 1" PrincipalType="User" /> 
    </Mapping>
    <Mapping>
      <Source AccountName="DOMAIN\xxxxx_yyyyyy2" DisplayName="Xxxxx Yyyyyy 1" PrincipalType="User" /> 
      <Destination AccountName="i:0#.f|membership|xxxxx.yyyyyy2@mydomain.com" DisplayName="Xxxxx Yyyyyy 2" PrincipalType="User" /> 
    </Mapping>
  </Mappings>
</UserAndGroupMappings>

Ainsi, dans mon cas, j’ai la chance d’avoir une base de données de référence avec tous les utilisateurs existants et valides dans le domaine.

Le script PowerShell permet donc de:

  • Se connecter à la collection de sites
  • Obtenir la liste de tous les utilisateurs de la collection (SPUsers List)
  • Tester chaque utilisateur dans la base de données
  • Créer le bloc XML de mapping

Une fois terminé, le script crée le fichier XML avec l’extension acceptée par ShareGate.

[string]$ConnectionString = "Data Source=MySQLServer;Integrated Security=True;Initial Catalog=MyDatabase;uid=MyAccount;pwd=MyPassword"
[string]$ProfileTable = "MyInternalUserTable"
[bool]$Verbose = $false
[int]$GLOBAL:TotalUsersUpdated = 0

[int]$NumberRow = 0
[string]$CleanedDestination_DisplayName = ""
[string]$CleanedSource_DisplayName = ""

[string]$MappingFileExported = "C:\TEMP\ShareGate-Create-UserMapping-SiteCollection\_SGS-UserAndGroupMappings-$(get-date -f yyyyMMdd-HHmm).sgum"

function GetSQLToDataSet([string]$sql)
{
    if($Verbose){Write-Host "SQL: ", $sql}

    $sqlCon = New-Object Data.SqlClient.SqlConnection
    $sqlCon.ConnectionString = $ConnectionString
    $ds = new-object "System.Data.DataSet" "MyDataSet"
    $da = new-object "System.Data.SqlClient.SqlDataAdapter" ($sql, $sqlCon)
    $da.Fill($ds)
    Write-Host "   DataSet.Table Row Number:", $ds.Tables[0].Rows.Count

    $sqlCon.close()
    $sqlCon.dispose()
    $table = new-object system.data.datatable
    $table = $set.Tables[0]
    return $table
}

function GetDataTablewithExecuteReader ([string]$SQLQuery)
{
    if($Verbose){Write-Host "SQL: ", $SQLQuery}

    $Datatable = New-Object System.Data.DataTable
    $Connection = New-Object System.Data.SQLClient.SQLConnection
    $Connection.ConnectionString = $ConnectionString
    $Connection.Open()
    $Command = New-Object System.Data.SQLClient.SQLCommand
    $Command.Connection = $Connection
    $Command.CommandText = $SQLQuery
    $Reader = $Command.ExecuteReader()
    $Datatable.Load($Reader)
    $Connection.Close()
    Write-Host "   DataTable Row Number:", $Datatable.Rows.Count

    return $Datatable
}

function Get-All-SiteCollection-Users([string]$SiteCollectionURL)
{
    $Datatable = New-Object System.Data.DataTable
    $Connection = New-Object System.Data.SQLClient.SQLConnection
    $Command = New-Object System.Data.SQLClient.SQLCommand
    $Connection.ConnectionString = $ConnectionString
    [string]$SQLCommandScript = ''
    [string]$AccountMappingXML = ''
   
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
    $site = new-object Microsoft.SharePoint.SPSite($SiteCollectionURL)
    $web = $site.openweb()

    #Debugging - show SiteCollectionURL
    write-host "SiteCollectionURL: ", $SiteCollectionURL
    Write-Output "SiteCollectionURL - $SiteCollectionURL"

    $siteCollUsers = $web.SiteUsers
    write-host "Users Items: ", $siteCollUsers.Count
    [string]$XMLFile = "<?xml version=""1.0""?> `n"
    $XMLFile += "<UserAndGroupMappings xmlns:xsd=""
http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""> `n  <Mappings> `n"

    foreach($MyUser in $siteCollUsers)
    {
        $NumberRow += 1
        if(($MyUser.LoginName.ToLower() -ne "sharepoint\system") -and ($MyUser.LoginName.ToLower() -ne "nt authority\authenticated users") -and ($MyUser.LoginName.ToLower() -ne "nt authority\local service"))
        {
            #Write-Host "  USER: ", $MyUser.LoginName
            $UserName = $MyUser.LoginName.ToLower()
            Write-Host " >> User Login: ", $MyUser.LoginName
           
            $SQLCommandScript = "SELECT USER_NTNAME AS Source_AccountName, USER_PREFERRED_NAME AS Source_DisplayName, CASE LEN(USER_EMAIL) WHEN 0 THEN 'i:0#.f|membership|'+ (RIGHT(USER_NTNAME,LEN(USER_NTNAME)-CHARINDEX('\',USER_NTNAME)) + '@yourtenant.onmicrosoft.com') ELSE 'i:0#.f|membership|'+ USER_EMAIL END AS Destination_AccountName, (USER_LAST_NAME +', '+ USER_FIRST_NAME +' ('+ USER_CITY +')') AS Destination_DisplayName FROM [metricsops].[dbo].[MOSSProfileDataToWSS] WHERE USER_NTNAME = '$($MyUser.LoginName.ToLower())' ORDER BY USER_NTNAME ASC"
            #Write-Host "SQL: ", $SQLCommandScript
           
            $Datatable.Clear()
            $Connection.Open()
            $Command.Connection = $Connection
            $Command.CommandText = $SQLCommandScript
            $Reader = $Command.ExecuteReader()
            $Datatable.Load($Reader)
            $Connection.Close()
            Write-Host "   DataTable Row Number:", $Datatable.Rows.Count
 
            if ($Datatable.Rows.Count -gt 0)
            {
                foreach($myUserDataMapping in $Datatable.Rows)
                {
                    $CleanedDestination_DisplayName =  $myUserDataMapping.Destination_DisplayName -replace "&", " "
                    $CleanedSource_DisplayName =  $myUserDataMapping.Source_DisplayName -replace "&", " "

                    Write-Host " "
                    Write-Host " ========================================================="
                    Write-Host "    Row Number:", $NumberRow, " of ", $siteCollUsers.count
                    Write-Host "    SharePoint Onpremise Account Name:", $myUserDataMapping.Source_AccountName
                    Write-Host "    SharePoint Onpremise Display Name:", $CleanedSource_DisplayName
                    Write-Host "    O365 Destination Account Name:", $myUserDataMapping.Destination_AccountName
                    Write-Host "    O365 Destination Display Name:", $CleanedDestination_DisplayName
                    Write-Host " ---------------------------------------------------------"
                   
                    $AccountMappingXML = "    <Mapping> `n"
                    $AccountMappingXML += "      <Source AccountName=""$($myUserDataMapping.Source_AccountName)"" DisplayName=""$($CleanedSource_DisplayName)"" PrincipalType=""User"" />  `n"
                    $AccountMappingXML += "      <Destination AccountName=""$($myUserDataMapping.Destination_AccountName)"" DisplayName=""$($CleanedDestination_DisplayName)"" PrincipalType=""User"" />  `n"
                    $AccountMappingXML += "    </Mapping> `n"

                    $XMLFile += $AccountMappingXML
                }
            }
        }
    }

    $GLOBAL:TotalUsersUpdated += 1
    $XMLFile += "  </Mappings> `n </UserAndGroupMappings>"
    $XMLFile >> $MappingFileExported

    $web.Dispose()
    $site.Dispose()
}

function StartProcess()
{
    # Create the stopwatch
    [System.Diagnostics.Stopwatch] $sw;
    $sw = New-Object System.Diagnostics.StopWatch
    $sw.Start()
    #cls

    Get-All-SiteCollection-Users http://MySharePoint2007WebApp/sites/MySitecollection

    $sw.Stop()

    # Write the compact output to the screen
    write-host "Time: ", $sw.Elapsed.ToString()
}

StartProcess

Il vous faudra juste adapter le script pour le test des utilisateurs selon votre propre configuration.

Fabrice Romelard [MBA Risk Management]

----

Une autre solution proposée par le Support de ShareGate (très actif d'ailleurs) est de passer par la fonction de chargement des CSV depuis ShareGate directement:

----

XML User Mapping

I saw your last e-mail with the workaround. Just so you know we have our own Powershell cmdlet that could help you create an SGUM file based on a csv. Here's an example:

#Here is how you can fill your CSV file. In the current example, my two columns are named SourceValue and DestinationValue, and we will set the variable $csvFile:

$csvFile = "C:\CSVfile.csv"

csv content:

SourceValue,DestinationValue

John Doe,Johnny Doe

Mary Doe,Maria Doe

etc...

# Create a table based on the csv file:

$table = Import-Csv $csvFile -Delimiter ","

# Declaration of the mapping settings:

$mappingSettings = New-MappingSettings

# Cycle through each row of the csv file:

foreach ($row in $table)

{

#add the current row's source user and destination user to the list of mappings

Set-UserAndGroupMapping -MappingSettings $mappingSettings -Source $row.SourceValue -Destination $row.DestinationValue

}

# The user and group mappings are exported to:

C:\FolderName\FileName.sgum

Export-UserAndGroupMapping -MappingSettings $mappingSettings -Path C:\FolderName\FileName

---

Fabrice

Commentaires

Posts les plus consultés de ce blog

Redonner vie à une Microsoft Surface RT : le guide ultime vers Linux !

Vous avez une vieille Microsoft Surface RT qui traîne dans un tiroir ? Vous savez, cette tablette de 2012 devenue inutilisable depuis l'abandon officiel de Windows RT par Microsoft ? Ne la jetez surtout pas ! Dans ma dernière vidéo, je vous montre comment transformer cet appareil, autrefois considéré comme un "presse-papier", en une tablette Linux moderne et parfaitement fonctionnelle . Pourquoi ce projet ? L'objectif est simple : transformer ce matériel pour en faire un dashboard dédié à mon système Home Assistant. En installant postmarketOS , une version de Linux spécialement conçue pour les appareils ARM abandonnés, on redonne une seconde jeunesse à cette machine . Ce que vous allez apprendre dans ce tutoriel complet : La libération du matériel : Comment réinstaller la version d'origine pour passer outre les blocages de Windows 8.1 . Jailbreak & Secure Boot : La procédure indispensable pour déverrouiller la machine et permettre l'installation d...

Série de Videos sur Home Assistant intégrant la production Photovoltaïque

 Un certain nombre de vidéos sont en ligne pour intégrer sa production photovoltaïque dans Home Assistant en partant de la base. Installation de Home Assistant: On peut ensuite intégrer les composant des Micro-Onduleurs Enphase, mais aussi les batteries Enphase: Ou encore le composant de contrôle Ecojoko: Ce qui permet alors de faire des comparaisons entre les valeurs capturées: Des videos seront encore publiés dans les prochaines semaines sur différents aspects de cette solution. Fab

Mixer les batteries Enphase et Zendure : La solution ultime pour l'autoconsommation ?

Introduction Vous avez déjà une installation solaire équipée de micro-onduleurs Enphase , mais vous trouvez que le stockage officiel de la marque est trop coûteux ou difficile à installer en DIY ? Vous n'êtes pas seul. Aujourd'hui, je vous partage mon retour d'expérience complet sur une configuration qui intrigue beaucoup de monde : le couplage d'un système Zendure SolarFlow avec un environnement Enphase existant. Pourquoi vouloir mixer ces deux marques ? Le système Enphase est une référence en termes de fiabilité, mais l'ajout de batteries IQ Battery peut représenter un investissement lourd. À l'inverse, Zendure propose avec le SolarFlow une solution de stockage plug-and-play extrêmement flexible et souvent plus abordable. L'idée est simple : utiliser le SolarFlow comme "tampon" entre vos panneaux et vos micro-onduleurs pour stocker l'excédent de la journée et le réinjecter la nuit. Le montage : Est-ce vraiment compliqué ? Dans ma dernière ...