Table des matières

Configurer une application enregistrée dans Entra ID pour gérer une équipe Sharepoint

Inscription d'une application

Une inscription d’application dans Entra se fait :

Installer le module Microsoft.Graph de Powershell

Installer Powershell 7

Installer Microsoft.Graph de Powershell

Install-Module Microsoft.Graph 
Import-Module Microsoft.Graph

Préparation Azure AD (OAuth2)

Depuis l'interface d'administration du portail Azure

Une autorisation d'application ne nécessite pas de compte utilisateur :

  • L'application agit en autonomie (service, script, automatisation).
  • Nécessite un consentement administrateur.

En CLI

Connect-MgGraph -Scopes "Application.ReadWrite.All","AppRoleAssignment.ReadWrite.All"
Welcome to Microsoft Graph!

Connected via delegated access using 14d82eec-204b-4c2f-b7e8-296a70dab67e
Readme: https://aka.ms/graph/sdk/powershell
SDK Docs: https://aka.ms/graph/sdk/powershell/docs
API Docs: https://aka.ms/graph/docs

NOTE: You can use the -NoWelcome parameter to suppress this message.
$app = New-MgApplication -DisplayName "Application"
$sp = New-MgServicePrincipal -AppId $app.AppId

Autoriser l'app enregistrée à mettre à jour les dossiers de l'équipe Teams

Cela ne peut pas se faire depuis l'interface d'administration Entra ID mais en utilisant Powershell.

Utilisation d'un certificat

$cert = New-SelfSignedCertificate `
  -Subject "CN=applicaton" `
  -CertStoreLocation "Cert:\CurrentUSer\My" `
  -KeySpec Signature `
  -KeyUsage DigitalSignature `
  -KeyExportPolicy Exportable `
  -HashAlgorithm SHA256 `
  -KeyLength 2048 `
  -NotAfter (Get-Date).AddYears(4)
$cert.Thumbprint
Get-Item "Cert:\CurrentUSer\My\<TON_THUMBPRINT>"
$cert = Get-Item "Cert:\CurrentUSer\My\<THUMBPRINT>"
$cert.HasPrivateKey

$cert.HasPrivateKey doit renvoyer True

Export du certificat PUBLIC (.cer) à importer dans Entra ID

Export-Certificate `
    -Cert "Cert:\CurrentUSer\My\$($cert.Thumbprint)" `
    -FilePath "application.cer"
Connect-MgGraph `  
   -TenantId "<TENANT_ID>" `  
   -ClientId "<APP_ID>" `  
   -CertificateThumbprint "<THUMBPRINT>" 

=> Résultat attendu
Plain TextWelcome To Microsoft Graph!
Get-MgContext

=> on doit voir :

ClientId               : <id client>
TenantId               : <ID tenant>
Scopes                 : {Sites.Selected}
AuthType               : AppOnly
TokenCredentialType    : ClientCertificate
CertificateThumbprint  : <empreinte>

Exporter le certificat pour obtenir un PFX PKCS#1 (clé privée incluse)

$thumb = "EMPREINTE_DU_CERTIFICAT"

$cert = Get-Item "Cert:\CurrentUser\My\$thumb"

Export-PfxCertificate `
  -Cert $cert `
  -FilePath "graph-auth.pfx" `
  -Password (ConvertTo-SecureString -String "MotDePasseFort123!" -AsPlainText -Force)

Importer un PFX sur une autre machine

Import-PfxCertificate `
   -FilePath "fichier.pfx" `
   -CertStoreLocation Cert:\CurrentUser\My `  
   -Password (ConvertTo-SecureString -String "MotDePasseFort123!" -AsPlainText)

Générer une clé PKCS#8

$pfxPath = "c:\temp\fichier.pfx"
$pfxPassword = "TempPfxPassword!ChangeMe"

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(
    $pfxPath,
    $pfxPassword,
    [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
)
$rsa = $cert.PrivateKey
# Récupère les paramètres
$params = $rsa.ExportParameters($true)

# Crée un RSA moderne
$rsa2 = [System.Security.Cryptography.RSA]::Create()
$rsa2.ImportParameters($params)

# Export PKCS#8
$pkcs8 = $rsa2.ExportPkcs8PrivateKey()

$base64 = [System.Convert]::ToBase64String(
    $pkcs8,
    [System.Base64FormattingOptions]::InsertLineBreaks
)


$pem = @"
-----BEGIN PRIVATE KEY-----
$base64
-----END PRIVATE KEY-----
"@

$pem | Set-Content `
  -Path C:\Temp\fichier.key `
  -Encoding ASCII

Résumé .cer .pfx

Un fichier .cer contient uniquement la clé publique du certificat. Cela permet :

  • de déclarer le certificat dans Entra ID
  • permet à Microsoft de vérifier les signatures

La clé privée est déjà stockée dans Windows :

  • dans Cert:\LocalMachine\My ou Cert:\CurrentUser\My
  • aucun PFX n’est nécessaire tant que l'on se connecte depuis le PC où se trouve la clé privée. En indiquant l'empreinte de la clé (thumbprint), cela permet de sélectionner la bonne clé privée.

Un fichier .cer ne permet pas :

  • de s’authentifier
  • de signer

Un fichier .pfx (format PFX / PKCS#12) contient :

  • la clé publique
  • la clé privée
  • (optionnel) la chaîne de certificats
  • et est protégé par une passphrase

C’est le seul format portable qui permet :

  • d’importer un certificat avec clé privée
  • d’authentifier une application sur une autre machine
  • d’utiliser le certificat sur Linux / AWX / Docker / CI/CD
Format Contient Usage
.cerclé publiqueEntra ID, SharePoint
.pfxclé publique + clé privéeAuthentification
.pfx + mdpportable sécuriséServeur, automatisation

Donner accès à l'application sur le site Sharepoint

# deconnexion
Disconnect-MgGraph

# Connexion admin
Connect-MgGraph -Scopes "Sites.FullControl.All"

# Récupérer le site
$site = Get-MgSite -SiteId "mondomaine.sharepoint.com:/sites/MonSite"

# Donner accès controle total à l'application (fullcontrol / read / write)
New-MgSitePermission `
  -SiteId $site.Id `
  -Roles "fullcontrol" `
  -GrantedToIdentities @{
      Application = @{
          Id = "ID application"
          DisplayName = "application"
      }
  }
Connect-MgGraph `  
   -TenantId "<TENANT_ID>" `  
   -ClientId "<APP_ID>" `  
   -CertificateThumbprint "<THUMBPRINT>" 
Get-MgSite -SiteId "mondomaine.sharepoint.com:/sites/MonSite"

Créer un dossier dans le site SharePoint

$site = Get-MgSite -SiteId "mondomaine.sharepoint.com:/sites/MonSite"
$site.Id

=> Afficher le GUID du site du type :
xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$drive = Get-MgSiteDrive -SiteId $site.Id
$drive.Id

=> Affiche un DriveId
Type : documentLibrary
New-MgDriveRootChild `
  -DriveId $drive.Id `
  -AdditionalProperties @{
      "name" = "Test-Dossier"
      "folder" = @{}
      "@microsoft.graph.conflictBehavior" = "rename"
  }


=> Résultat attendu
Id   : 01ABCDEF....
Name : Test-Dossier
=> Dossier créé avec succès à vérifier dans SharePoint
$items = Get-MgDriveRootChild -DriveId $drive.Id
$parent = $items | Where-Object { $_.Name -eq "General" }
$parent.Id
New-MgDriveItemChild `
  -DriveId $drive.Id `
  -DriveItemId $parent.Id `
  -AdditionalProperties @{
      "name" = "Test-SousDossier"
      "folder" = @{}
      "@microsoft.graph.conflictBehavior" = "rename"
  }

Installer le module module PnP.PowerShell

PnP.PowerShell supporte :

Install-Module PnP.PowerShell -Scope CurrentUser

Se connecter

$cert = New-SelfSignedCertificate `
    -Subject "CN=MinioS3Sync" `
    -KeyAlgorithm RSA `
    -KeyLength 2048 `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -NotAfter (Get-Date).AddYears(3)
Export-Certificate `
    -Cert $cert `
    -FilePath "./minio-s3.cer"
$password = Read-Host "Mot de passe du certificat" -AsSecureString

Export-PfxCertificate `
    -Cert $cert `
    -FilePath "./minio-s3.pfx" `
    -Password $password
``
Connect-PnPOnline `
  -Url "https://educvaladonlimogesfr-admin.sharepoint.com" `
  -ClientId "ad39ff78-4116-43d6-86cf-3dfa8f120aa3" `
  -Tenant "educvaladonlimogesfr.onmicrosoft.com" `
  -CertificatePath "./minio-s3.pfx" `
  -CertificatePassword $password

Donner l'autorisation

Grant-PnPAzureADAppSitePermission `
  -AppId "ad39ff78-4116-43d6-86cf-3dfa8f120aa3" `
  -DisplayName "Minio-S3c" `
  -Site "https://educvaladonlimogesfr.sharepoint.com/sites/Signaturenumrique" `
  -Permissions Write

Tester la commande

Connect-PnPOnline -Url "https://<tenant>-admin.sharepoint.com" -ClientId "<appID>" -ClientSecret "<secret>"

Script bash pour configurer l'accès à l'équipe Sharepoint associée à l'équipe Teams

Le script :

apt install jq
setup_sharepoint_access.sh
#!/usr/bin/env bash
 
### ---------------------------------------------------------------------------
###  CONFIGURATION À RENSEIGNER
### ---------------------------------------------------------------------------
 
TENANT_ID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
CLIENT_ID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
CLIENT_SECRET="YOUR_APP_SECRET"
 
HOSTNAME="contoso.sharepoint.com"          # domaine SharePoint
SITE_PATH="DocumensoSite"                  # nom du site SharePoint
DRIVE_NAME="Documents"                     # nom de la bibliothèque (ex: "Documents")
 
RCLONE_REMOTE="sharepoint"                 # nom du remote rclone
RCLONE_MINIO="s3minio:documenso"           # bucket minio
RCLONE_SHAREPOINT="${RCLONE_REMOTE}:${DRIVE_NAME}"
 
### ---------------------------------------------------------------------------
echo "1. Obtention du token OAuth2..."
 
ACCESS_TOKEN=$(
curl -s -X POST \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=$CLIENT_ID" \
  -d "scope=https://graph.microsoft.com/.default" \
  -d "client_secret=$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  "https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token" \
  | jq -r .access_token
)
 
if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then
  echo "❌ Impossible de générer un token ! Vérifie ton CLIENT_ID / SECRET."
  exit 1
fi
 
echo " Token obtenu."
 
### ---------------------------------------------------------------------------
echo "2. Récupération automatique du site-id..."
 
SITE_INFO=$(curl -s -X GET \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://graph.microsoft.com/v1.0/sites/$HOSTNAME:/sites/$SITE_PATH?$select=id,webUrl")
 
SITE_ID=$(echo "$SITE_INFO" | jq -r '.id')
 
if [[ "$SITE_ID" == "null" || -z "$SITE_ID" ]]; then
  echo "❌ Impossible de récupérer le site-id !"
  echo "Réponse brute:"
  echo "$SITE_INFO"
  exit 1
fi
 
echo " SITE_ID trouvé : $SITE_ID"
 
### ---------------------------------------------------------------------------
echo "3. Récupération automatique du drive-id de la bibliothèque $DRIVE_NAME..."
 
DRIVES_LIST=$(curl -s -X GET \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  "https://graph.microsoft.com/v1.0/sites/$SITE_ID/drives")
 
DRIVE_ID=$(echo "$DRIVES_LIST" | jq -r ".value[] | select(.name==\"$DRIVE_NAME\") | .id")
 
if [[ -z "$DRIVE_ID" ]]; then
  echo "❌ Impossible de trouver la bibliothèque '$DRIVE_NAME'"
  echo "Réponse brute:"
  echo "$DRIVES_LIST"
  exit 1
fi
 
echo "DRIVE_ID trouvé : $DRIVE_ID"
 
### ---------------------------------------------------------------------------
echo "4. Attribution de la permission Sites.Selected (write) à l'application..."
 
ASSIGN_RESPONSE=$(curl -s -X POST \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"roles\": [\"write\"],
    \"grantedToIdentities\": [
      {
        \"application\": {
          \"id\": \"$CLIENT_ID\"
        }
      }
    ]
  }" \
  "https://graph.microsoft.com/v1.0/sites/$SITE_ID/permissions")
 
echo " Permission appliquée."
echo "Réponse API :"
echo "$ASSIGN_RESPONSE"
 
### ---------------------------------------------------------------------------
echo "5. Test d'accès SharePoint avec rclone..."
 
docker exec -it rclone-sync rclone lsd "$RCLONE_SHAREPOINT"
 
echo " Configuration terminée avec succès !"
echo "SITE_ID  = $SITE_ID"
echo "DRIVE_ID = $DRIVE_ID"
 
bash setup_sharepoint_access.sh