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


Monday, May 11, 2026

Some basics to control QLC+ with Reaper using MIDI - Network Midi

Here's how you can do some basic control of QLC+ scenes using Reaper using MIDI but across your network.  

In this case, Reaper is running on 1 computer, and QLC+ on a second computer.
Reaper is playing a track, and I've created midi 'notes' that trigger effects in QLC+

This is using Windows 11

Download rtpMIDI by Tobias Erichsen

Install this application on both systems, in this example, on the REAPER and on the QLC system


Will look something like this:


On the system running Reaper:

In "MY SESSIONS" select + 
By default the system name of your computer will show up.  Enable it.


On the QLC computer, launch the rtpMIDI app
If under "Directory" the computer name doesn't show up, press the + button under directory box and enter in the IP of your Reaper computer.  Use port 5004

Under "my session" box, click the + button
The name of your local QLC computer should appear.  Click the CHECK box beside it.


Click on CONNECT



Launch QLC+

In the Inputs/Outputs tab

Set MIDI device that matches the computer name in the "My Session" box above.  Set it for = INPUT




In the profile tab, set to Generic MIDI


Open a scene that you have created and go to "Virtual Console"

Here is an example scene with 2 mover scenes, and 2 static light scenes



Double click a scene that you want to set a MIDI command to.  

Then select "Auto Detect"


Open up Reaper

In this example a track has been added that will have MIDI cues assigned to.


Goto OPTIONS - Preferences

Goto Audio - MIDI OUTPUTS

Hopefully you'll see the name of your Reaper computer.  Double click on that



ENABLE output to this device




In Reaper 

INSERT - New MIDI item


If your midi track doesn't contain "ROUTE" button as displayed here, enable it by selecting VIEW - ROUTING MATRIX


Select a point where you want to trigger a MIDI event


Double click on the new box

You'll basically see a piano keyboard on the side and a series of boxes.

We can use this to toggle an effect.

In this example, the note C4 was pressed, and then by clicking and dragging in the squares beside it, they have been made a red color.  This is the duration which the midi command is sent, but this is really fast, so you probably only need one little square selected vises the 5 in this example.  Exaggerated for effect.

In the lower right corner of this window, change the output to "CHANNEL 1"


You can close this window.  You'll now see your MIDI box, and you'll see a little black box in it.  That indicates when the midi command will be sent.




Click on the "ROUTE" button
Set the MIDI Hardware output to your computer name.  In this example, "BigDog"




Now with QLC in AUTO DETECT, if you press play as your timeline in reaper passes across the MIDI box, you should see the value in QLC change.

In this example, it changed to "189:C4"

And if you had a lights connected to that scene, they should have activated.

Every time that midi command is sent, it will toggle the scene on/off

You can speed up detection by using the programming by clicking on CHOOSE and see the values as they would be sent by the different piano keys in REAPER



In the example below, I'm sending MIDI commands to activate and deactivate sequences in QLC+






Some basics to control QLC+ with Reaper using MIDI - Local computer

Here's how you can do some basic control of QLC+ scenes using Reaper.

This is using Windows 11

Download loopMIDI by Tobias Erichsen

Install then run the app

Click on the "+" plus button in the corner and add a loopMIDI port. 


Launch QLC+

In the Inputs/Outputs tab

Set loopMIDI port = INPUT


In the profile tab, set to Generic MIDI


Open a scene that you have created and go to "Virtual Console"

Here is an example scene with 2 mover scenes, and 2 static light scenes



Double click a scene that you want to set a MIDI command to.  

Then select "Auto Detect"


Open up Reaper

In this example a track has been added that will have MIDI cues assigned to.


Goto OPTIONS - Preferences

Goto Audio - MIDI OUTPUTS

Hopefully you'll see "loopMIDI port".  Double click on that

ENABLE output to this device


In Reaper 

INSERT - New MIDI item


If your midi track doesn't contain "ROUTE" button as displayed here, enable it by selecting VIEW - ROUTING MATRIX


Select a point where you want to trigger a MIDI event


Double click on the new box

You'll basically see a piano keyboard on the side and a series of boxes.

We can use this to toggle an effect.

In this example, the note C4 was pressed, and then by clicking and dragging in the squares beside it, they have been made a red color.  This is the duration which the midi command is sent, but this is really fast, so you probably only need one little square selected vises the 5 in this example.  Exaggerated for effect.

In the lower right corner of this window, change the output to "CHANNEL 1"


You can close this window.  You'll now see your MIDI box, and you'll see a little black box in it.  That indicates when the midi command will be sent.




Click on the "ROUTE" button
Set the MIDI Hardware output to "loopMIDI port"


Now with QLC in AUTO DETECT, if you press play as your timeline in reaper passes across the MIDI box, you should see the value in QLC change.

In this example, it changed to "189:C4"

And if you had a lights connected to that scene, they should have activated.

Every time that midi command is sent, it will toggle the scene on/off

You can speed up detection by using the programming by clicking on CHOOSE and see the values as they would be sent by the different piano keys in REAPER



In the example below, I'm sending MIDI commands to activate and deactivate sequences in QLC+







Friday, May 8, 2026

Control VLC with web browser

 Goto Preferences


In the bottom change 
Show settings ALL



Click the arrow beside INTERFACES. Then select LUA (most tutorials don't mention that arrow)




Give it a password and save.   Then restart VLC



Open a browser and goto 
http://localhost:8080

Leave username blank and put in your password and click "SIGN IN"


You'll be prompted with a GUI version of the VLC interface that you can now control VLC with