Microsoft 365 e PowerShell

Acrive Directory in versione web

In fase di sviluppo Pagina in preparazione In fase di sviluppo

Microsoft 365, in precedenza noto come Office 365, sta diventando popolare nelle scuole come del resto il suo concorrente G Suite (nota 1). In questa pagina riporto alcune note disordinate su come gestisco oltre mille utenti della mia scuola, tipicamente gli studenti, i docenti ed il personale.

Questa pagina documenta il lavoro iniziato da Raffaele Milani e poi aggiornato nel corso degli anni.

In sintesi:

Alcuni aspetti preliminari

PowerShell (pwsh.exe) dovrebbe essere già presente sul sistema; se non lo è dovete installarlo o, meglio, reinstallare l'intero sistema operativo, direi davvero troppo vecchio... Quanto qui scritto utilizza la versione corrente alla data di scrittura del documento.

PowerShell è presente in due versioni, una come normale linea di comando e l'altra come PowerShell Integrated Scripting Environment (ISE) che permette alcune opzioni orientate al debug. Entrambe possono essere utilizzate; personalmente preferisco la ISE, soprattutto se si stanno utilizzando script.

Occorre permettere l'installazione di script locali, opzione disattiva per ragioni di sicurezza. Come amministratore in una finestra PS occorre digitare:

PS C:\Users\VincenzoV> Set-ExecutionPolicy Unrestricted

Inoltre occorre installare un modulo per l'accesso remoto, operazione piuttosto lunga e che richiede l'accettazione dell'uso di un repository non fidato, sempre come amministratore (nota 2):

PS C:\Users\VincenzoV> Install-Module MSOnline

Utile inoltre:

PS C:\Users\VincenzoV> Install-Module -Name MicrosoftTeams

Connettersi a Microsoft 365 remoto

Per connettersi al server remoto occorre conoscere la password di amministratore del dominio; per utilizzare un server Exchange con PowerShell ed usare il modulo MSol per la gestione di Azure occorre eseguire il seguente codice:

$LiveCred=Get-Credential -UserName admin@xxxx.it -Message "Inserisci le credenziali dell'amministratore"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession $Session
connect-msolservice -credential $LiveCred

Nel caso di utilizzo in una rete protetta da un proxy è necessario sostituire la seconda riga con le due seguenti, dopo aver configurato windows per l'utilizzo del proxy:

$proxysettings = New-PSSessionOption -ProxyAccessType IEConfig
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection -SessionOption $proxysettings

Importante: nel caso in cui sia utilizzato MFA (procedura peraltro vivamente consigliata!) verranno richieste due volte le credenziali di accesso. Al momento non ho trovato come aggirare questa seccatura...

Come spesso utile, conviene inserire tali comandi in uno script. Un esempio che utilizzo è allegato nel file compresso come 10 openConnection.ps.

Per collegarsi ad Azure AD è disponibile anche un altro modulo che in parte si sovrappone a MSol.

Caratteristiche degli utenti

Prima di iniziare, vediamo quali sono i campi principali che andremo ad utilizzare.

Studenti

L'interfaccia web di Azure Active Directory mostra un tipico studente come segue:

Uno studente

Di seguito l'elenco dei campi, relativi ad uno studente, con i nomi mostrati nell'immagine precedente e, in evidenza, con i nomi interni che utilizzeremo negli script:

Inoltre all'interno di Exchange è presente, solo per gli studenti, un attributo personalizzato (customattribute1) contenente il codice fiscale (nota 3):

Codice fiscale

Personale

Un docente

La configurazione di un account appartenente al personale è simile a quella degli studenti, ma evidentemente non contiene alcun riferimento alla classe; neppure contiene il codice fiscale.

Esempi

Vediamo qualche esempio PowerShell per estrarre informazioni su gruppi ed utenti. I primi tre esempi sono presenti nel file 20 recupero email e CF studenti.ps nel file compresso allegato, in quanto utilizzati in seguito.

Elencare la mail di tutti gli studenti di quinta, riconoscibili dal fatto che il Department inizia per 5:

PS C:\Users\Vincenzo Villa> Get-MsolUser -All -Title "Studente" | Where-Object {$_.Department.startswith("5")} | Select-Object UserPrincipalName
UserPrincipalName
-----------------
aaa.bbb@issgreppi.it
Paolo.Rossi@issgreppi.it

Se, come spesso succede, tale elenco deve essere importato in un foglio di lavoro è utile il cmdlet Out-GridView al termine.

Per elencare i campi principali di tutti gli studenti:

Get-MsolUser -All -Title "Studente" | Select-Object UserPrincipalName, FirstName, LastName, DisplayName, Title, Department | Out-GridView

Elenco studenti

Lo stesso comando, per gli utenti che non sono studenti:

Get-MsolUser -All | Where-Object {$_.Title -ne "Studente" } | Select-Object UserPrincipalName, FirstName, LastName, DisplayName, Title, Department

I campi di Exchange richiedono un diverso cmdlet. L'esempio seguente ritorna UserPrincipalName e customattribute1, quest'ultimo presente solo per gli studenti. Vengono elencati solo i primi 2 000 utenti (cioè... tutti).

Get-Mailbox -ResultSize 2000 |Where-Object {$_.customattribute1 -ne "" }| Select-Object UserPrincipalName, customattribute1

Per elencare i gruppi Sicurezza abilitata alla posta elettronica‎ ed i rispettivi membri occorre usare un paio di comandi Exchange:

PS C:\Users\Vincenzo Villa> Get-DistributionGroup
Name    DisplayName GroupType                  PrimarySmtpAddress
----    ----------- ---------                  ------------------
DOCENTI DOCENTI     Universal, SecurityEnabled DOCENTI@issgreppi.it
1IK     1IK         Universal, SecurityEnabled 1IK@issgreppi.it

PS C:\Users\Vincenzo Villa> Get-DistributionGroupMember -Identity DOCENTI
Name           RecipientType
----           -------------
vincenzo.villa UserMailbox
gabriele.xyz   UserMailbox

Elencare tutti i Teams (potrebbe impiegare molto tempo):

PS C:\Users\VincenzoV> Get-Team

Elencare i Teams ai quali un utente appartiene:

PS C:\Users\VincenzoV> Get-Team -User vincenzo.villa@xyz

Rimuovere i vecchi utenti

La prima operazione da fare è la rimozione in massa delle vecchie utenze:

Per cancellare gli utenti serve il loro indirizzo di mail. Tale elenco può essere creato in vari modi: a partire dall'elenco degli studenti di quinta, da un confronto tra gli iscritti e le utenze presenti in Microsoft 365, a mano... Tale elenco è salvato in un file (per esempio exstudenti.csv) con la seguente strutture:

PS C:\Users\Vincenzo Villa\script> cat .\exstudenti.csv
email
ANDREA.xxx@issgreppi.it
FRANCESCO.xxx@issgreppi.it
LAURA.xxx@issgreppi.it

Tali utenze vengono inserire in un gruppo specifico (per esempio ex-studenti), per esempio attraverso uno script simile al file 40 Aggiorna ex-studenti.ps1 presente nell'allegato e di seguito riportato:

$host.Runspace.ThreadOptions = "ReuseThread"
function Update-Office365UsersEx
{ # Reading the CSV file
   $bFileExists = (Test-Path $sInputFile -PathType Leaf)
   if ($bFileExists) {
      "Loading $InvFile for processing..."
      $tblDatos = Import-CSV $sInputFile}
   else {
      Write-Host "$sInputFile file not found. Stopping the import process!" -foregroundcolor Red
      exit
}
# updating the users
  Write-Host "Updating the Office 365 users for OLD user..." -foregroundcolor Green
  foreach ($riga in $tblDatos) {
    Write-Host "Updating user: " $riga.$email
    Set-MsolUser -UserPrincipalName $riga.$email -Department "EX-Studenti" -DisplayName $riga.$email
    Add-DistributionGroupMember -Identity "EX-Studenti" -Member $riga.$email
  }
}
$ScriptDir = Split-Path -parent $MyInvocation.MyCommand.Path
$sInputFile=$ScriptDir+ "\exstudenti.csv"
$email="email"
############ main ##########à
Update-Office365UsersEx

Se serve, il gruppo degli EX può essere creato con:

PS C:\Users\Vincenzo Villa\script> new-distributiongroup -name "EX-Studenti" -alias "EX-Studenti" -type "security" -primarysmtpaddress ("EX-Studenti" + "@issgreppi.it")

Prima di cancellare le utenze è cosa buona inviare, con un certo anticipo, una serie di mail che preavvisano la cancellazione.

Rimuovere le vecchie classi e creare le nuove

Questa operazione non rimuove utenti o dati, ma solo i gruppi Sicurezza abilitata alla posta elettronica, uno per ciascuna classe.

L'elenco può essere ottenuto dall'interfaccia web di amministrazione oppure con il comando (nota 5):

PS C:\Users\Vincenzo Villa> Get-DistributionGroup | Out-GridView

Elenco delle classi da interfaccia web

Questo file va quindi inserito in un file (per esempio gruppi-da-cancellare.csv) ed eseguito il seguente script 50 cancella_gruppi.ps1 (anche in allegato).

$host.Runspace.ThreadOptions = "ReuseThread"
function Remove-Office365Groups
{# Reading the CSV file
 $bFileExists = (Test-Path $sInputFile -PathType Leaf)
 if ($bFileExists) {
 "Loading $InvFile for processing..."
 $tblDatos = Import-CSV $sInputFile
} else {
 Write-Host "$sInputFile file not found. Stopping the import process!" -foregroundcolor Red
 exit
}
# Deleting the groups
Write-Host "Deleting the Office 365 groups ..." -foregroundcolor Green
foreach ($fila in $tblDatos)
{Write-Host "Deleting group " + $fila.$sColumnName
 Remove-DistributionGroup -Identity $fila.$sColumnName -BypassSecurityGroupManagerCheck
}
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
Write-Host "All the group have been deleted. The processs is completed." -foregroundcolor Green
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
}
######### main ###########
$ScriptDir = Split-Path -parent $MyInvocation.MyCommand.Path
$sInputFile=$ScriptDir+ "\gruppi-da-cancellare.csv"
$sColumnName="gruppo"
Remove-Office365groups

Gruppi classi da rimuovere e creare

Successivamente occorre creare i nuovo gruppi classe (file gruppi-da-creare.csv, da documenti della segreteria) ed eseguire lo script 60 crea gruppi.ps1, anche in allegato.

$host.Runspace.ThreadOptions = "ReuseThread"
function CreaGruppi
{$bFileExists = (Test-Path $sInputFile -PathType Leaf)
 if ($bFileExists) {
 "Loading $InvFile for processing..."
 $tblDatos = Import-CSV $sInputFile
} else { Write-Host "$sInputFile file not found. Stopping the import process!" -foregroundcolor Red
 exit
}
foreach ($fila in $tblDatos)
{"Group: " + $fila.$sColumnName
 new-distributiongroup -name $fila.$sColumnName -alias $fila.$sColumnName -type "security" -primarysmtpaddress  ($fila.$sColumnName + "@issgreppi.it")
}
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
Write-Host "The processs is completed." -foregroundcolor Green
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
}
$ScriptDir = Split-Path -parent $MyInvocation.MyCommand.Path
$sInputFile=$ScriptDir+"\gruppi-da-creare.csv"
$sColumnName="gruppo"
######## main ##########
CreaGruppi

Creare i nuovi utenti ed aggiornare i dati

Gli utenti possono essere creati o modificati manualmente (quando sono poche unità) oppure in blocco, operazione che verrà qui descritta per gli studenti, sicuramente l'aspetto numericamente più importante.

Il punto di partenza è il file, contenente per ciascuno studente una riga con i seguenti campi:

Questo file viene dato in pasto allo script 70 aggiorna anagrafica studenti.ps1, in due passaggi:

  1. Il primo per creare le utenze non ancora esistenti
  2. Il secondo per aggiornare tutte le utenze, tipicamente modificando la classe. Il secondo giro deve essere fatto diversi minuti dopo il primo, per attendere l'assestarsi del sistema

I due passi sono impostati attraverso un'apposita variabile, di seguito evidenziata, da settare come CREA oppure AGGIUNGIALGRUPPO.

$host.Runspace.ThreadOptions = "ReuseThread"
function Update-Office365Users
{$bFileExists = (Test-Path $sInputFile -PathType Leaf)
 if ($bFileExists) {
 "Loading $InvFile for processing..."
 $tblDatos = Import-CSV $sInputFile
} else {
 Write-Host "$sInputFile file not found. Stopping the import process!" -foregroundcolor Red
 exit
}
# updating the users
Write-Host "Updating the Office 365 users ..." -foregroundcolor Green
foreach ($riga in $tblDatos)
{if ($riga.$tipo -eq "AGGIORNARE")
  {if ($creaoassegnagruppo -eq "CREA")
    {Write-Host "Updating user " + $riga.$email
     Set-MsolUser -UserPrincipalName $riga.$email -Department $riga.$classe -DisplayName $riga.$displayname
     Add-DistributionGroupMember -Identity $riga.$classe -Member $riga.$email }
  }
else
  {Write-Host "Creating new user: " $riga.$email
   if ($creaoassegnagruppo -eq "CREA")
      {#crea nuovo utente con licenze standard
       New-MsolUser -Title 'STUDENTE' –Department $riga.$classe -FirstName $riga.$nome -DisplayName $riga.$displayname -LastName $riga.$cognome -Password $riga.$pwd -UserPrincipalName $riga.$email -UsageLocation IT -LicenseAssignment $riga.$lic1
      }
else
{#assegna l'account al gruppo classe
 Add-DistributionGroupMember -Identity $riga.$classe -Member $riga.$email
 #imposta il codice fiscale in un campo customattribute nascosto
 Set-Mailbox -CustomAttribute1 $riga.$cf -Identity $riga.$email
 Set-MsolUser -UserPrincipalName $riga.$email -Department $riga.$classe -DisplayName $riga.$displayname
}
}
}
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
Write-Host "All the users have been updated. The processs is completed." -foregroundcolor Green
Write-Host "-----------------------------------------------------------" -foregroundcolor Green
}
$ScriptDir = Split-Path -parent $MyInvocation.MyCommand.Path
$sInputFile=$ScriptDir+ "\studenti-aggiorna.csv"
$logFile=$ScriptDir+ "\studenti.csv"
$tipo="tipo"
$classe="classe"
$nome="nome"
$cognome="cognome"
$displayname="displayname"
$cf="cf"
$pwd="pwd"
$email="email"
$lic1="lic1"
$lic2="lic2"

$creaoassegnagruppo="CREA"
#$creaoassegnagruppo="AGGIUNGIALGRUPPO"

Update-Office365Users

Altre informazioni

Qualche altra pagina legata all'amministrazione di Microsoft 365 tramite PowerShell:

Note

  1. Non intendo qui discutere se sia giusto o meno cedere la libertà di docenti e studenti ad una multinazionale solo perché fornisce gratuitamente un servizio. Dico solo che sono servizi comodi...
  2. Queste indicazioni scandalose sono presenti nel tutorial ufficiale Microsoft...
  3. La ragione è storica; penso prossimamente di cambiare questa impostazione
  4. In genere l'esecuzione degli script è, giustamente, limitata. Per eseguire script locali non firmati: Set-ExecutionPolicy Unrestricted ; per verificare lo stato della policy: Get-ExecutionPolicy
  5. Non tutti i gruppi Sicurezza abilitata alla posta elettronica sono classi
  6. Tale procedura vale anche per un gruppo Sicurezza abilitata alla posta elettronica
  7. Questa scelta ha ragioni storiche, oggi si potrebbe usare per esempio il campo ID dipendente

Allegati

Scarica gli script di esempio


Data di creazione di questa pagina: aprile 2020
Ultima modifica di questa pagina: 26 agosto 2020


Pagina principaleAccessibilitàNote legaliPosta elettronicaXHTML 1.0 StrictCSS 3

Vai in cima