Wednesday, May 20, 2026

Update 365 Tenant user information using powershell and csv file

This script I use to update employee job titles and managers.  It runs monthly for us to sync employee changes in their job titles and managers.  This detects if you try and add a manger that is 'below' the user's current status.  Meaning you can add yourself as a manger to yourself.  Nor could you add an employee that was your subordinate as a manger to yourself.

Create a file called UserUpdates.csv and put in the comma delimited data.

UserPrincipalName,ManagerUPN,JobTitle,Department,OfficeLocation
user1@company.com,manager1@company.com,Systems Administrator,IT,NYC
user2@company.com,manager2@company.com,Network Supervisor,ITOP,FLA

Create a new file called UpdateUser.ps1

Change the path in the script to reflect the path your csv file is located
$csvPath = "C:\updates\UserUpdates.csv"

run the script in powershell (as admin)  .\UpdateUser.ps1

the script will prompt you for a user with rights to make the changes, usually some administrator of the tenant.  Then it will run the script a line at a time.

At time of writing, the prompt that worked for me would look like this style below:  And I would select my admin user that had creds.  I found that sometimes it would give me a different looking one, and i would have to run the script again, because it would ask for creds every single time it ran a new line in the csv. 



# ###########################
# Cobbled together with CoPilot and ChatGTP
# Update the following items via a CSV
# - Manager  Job  Title  Department  Office Location
#
# Added circular hierarchy validation
# Uses Microsoft Graph PowerShell SDK
# #############################

# Install module if needed:
# Install-Module Microsoft.Graph -Scope CurrentUser

Import-Module Microsoft.Graph.Users

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.ReadWrite.All"

# UserPrincipalName,ManagerUPN,JobTitle,Department,OfficeLocation
# user1@company.com,manager@company.com,Systems Administrator,IT,NYC

$csvPath = "C:\updates\UserUpdates.csv"

# Import CSV
$users = Import-Csv -Path $csvPath

# ###########################
# Function: Detect/Prevent Circular Management Structure
# ###########################

function Test-ManagerCircularReference {

    param (
        [string]$UserId,
        [string]$ManagerId
    )

    # Prevent self-manager assignment
    if ($UserId -eq $ManagerId) {
        return $true
    }

    $currentManagerId = $ManagerId

    while ($currentManagerId) {

        # Detect circular hierarchy
        if ($currentManagerId -eq $UserId) {
            return $true
        }

        try {

            $manager = Get-MgUserManager `
                -UserId $currentManagerId `
                -ErrorAction Stop

            if ($manager.Id) {
                $currentManagerId = $manager.Id
            }
            else {
                $currentManagerId = $null
            }
        }
        catch {
            $currentManagerId = $null
        }
    }

    return $false
}

# ###########################
# Process the CSV file
# ###########################

foreach ($entry in $users) {

    $userUPN        = $entry.UserPrincipalName.Trim()
    $managerUPN     = $entry.ManagerUPN.Trim()
    $jobTitle       = $entry.JobTitle.Trim()
    $department     = $entry.Department.Trim()
    $officeLocation = $entry.OfficeLocation.Trim()

    Write-Host ""
    Write-Host "Processing: $userUPN" -ForegroundColor Cyan

    try {

        # ###########################
        # Get User
        # ###########################

        $user = Get-MgUser `
            -UserId $userUPN `
            -ErrorAction Stop

        # ###########################
        # Update User Properties
        # ###########################

        Update-MgUser `
            -UserId $user.Id `
            -JobTitle $jobTitle `
            -Department $department `
            -OfficeLocation $officeLocation

        Write-Host "SUCCESS: Updated user profile properties." `
            -ForegroundColor Green

        # ###########################
        # Update Manager (if provided)
        # ###########################

        if (![string]::IsNullOrWhiteSpace($managerUPN)) {

            $manager = Get-MgUser `
                -UserId $managerUPN `
                -ErrorAction Stop

            # Validate hierarchy
            $hasCircularReference = Test-ManagerCircularReference `
                -UserId $user.Id `
                -ManagerId $manager.Id

            if ($hasCircularReference) {

                Write-Host "SKIPPED: Circular hierarchy detected." `
                    -ForegroundColor Yellow
            }
            else {

                Set-MgUserManagerByRef `
                    -UserId $user.Id `
                    -BodyParameter @{
                        "@odata.id" = "https://graph.microsoft.com/v1.0/users/$($manager.Id)"
                    }

                Write-Host "SUCCESS: Updated manager." `
                    -ForegroundColor Green
            }
        }
        else {

            Write-Host "INFO: No manager specified." `
                -ForegroundColor DarkYellow
        }
    }

    catch {

        Write-Host "FAILED: $($_.Exception.Message)" `
            -ForegroundColor Red
    }
}

# Disconnect Graph Session
Disconnect-MgGraph

Write-Host ""
Write-Host "Processing complete." -ForegroundColor Cyan


No comments:

Post a Comment

Feel free to leave a comment! If you have any information that you think should be included, please do so here and I'll get it added in.