The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何透過 Microsoft Graph PowerShell 設定使用者的 M365 授權

微軟的 MSOnline, AzureAD, Microsoft Graph, ... PowerShell 模組歷經了好幾個世代,我覺得越改越複雜、越改越難用,今天我遇到了第一代的 Cmdlet 某個用法被停用的狀況,導致我被迫必須升級到最新版來改寫我的自動化腳本,這篇文章就來記錄一下我遇到的問題與解法。

問題描述

我公司只要有新進同仁時,我就會用 New-MsolUser Cmdlet 命令來建立帳號:

New-MsolUser -UserPrincipalName $UserPrincipalName -DisplayName $DisplayName -FirstName $FirstName -LastName $LastName -UsageLocation $UsageLocation -MobilePhone $MobilePhone -Office $Office -PhoneNumber $PhoneNumber -PreferredLanguage $PreferredLanguage -State $State -StreetAddress $StreetAddress -Title $Title -AlternateEmailAddresses $AlternateEmailAddresses -Country $Country -PostalCode $PostalCode -City $City -Department $Department -Fax $Fax -LicenseAssignment $LicenseAssignment

這段命令最關鍵的地方是 -LicenseAssignment 參數,這個參數可以指定要給新進同仁哪些授權,我們公司的授權是透過 Microsoft 365 E3 企業版,所以你必須明確指定授權給新建立的帳號。不過,我今天在建立帳號時,遇到了 New-MsolUser : Unknown error occurred. 這個模糊的錯誤,完全看不出到底問題是什麼!

New-MsolUser : Unknown error occurred.

我拿錯誤訊息去 Google 查看看有沒有人遇到相同的問題,想不到也就在 2 天前才有人提問,且遇到問題的狀況跟我有點相似,但是他的問題是在 Set-MsolUserLicense Cmdlet 上。我原本不知道問題出在哪裡,看了這篇之後才驚覺可能是 -LicenseAssignment 參數造成的,我在移除這個參數後,帳號就可以順利建立成功! 👍

不過,我要怎樣用 PowerShell 來授權呢?只好硬著頭皮去學 Microsoft Graph SDK for PowerShell 的用法了!

安裝與更新 Microsoft Graph PowerShell

事實上 Microsoft Graph PowerShell SDK 包含兩個主要模組:

  1. Microsoft.Graph

    這套會呼叫 Microsoft Graph REST API v1.0

  2. Microsoft.Graph.Beta

    這套會呼叫 Microsoft Graph REST API beta

我們今天要用的是 Microsoft.Graph 模組,所以我就先講講這套如何安裝與更新:

  1. 安裝 Microsoft Graph PowerShell SDK

    最新版的 Microsoft.Graph 模組可以從 PowerShell Gallery 安裝,只要執行以下命令即可:

    Install-Module Microsoft.Graph -Scope CurrentUser
    

    由於 Microsoft.Graph 模組會連帶安裝 38 個子模組,所以第一次安裝的時間會有點久,請耐心等候。

    完整資訊請參見 Install the Microsoft Graph PowerShell SDK 官方文件。

  2. 驗證安裝 Microsoft Graph PowerShell SDK

    Get-InstalledModule Microsoft.Graph
    
  3. 更新安裝 Microsoft Graph PowerShell SDK

    你要從舊版升級到最新版的話,可以執行以下命令:

    Update-Module Microsoft.Graph
    
  4. 移除所有 Microsoft Graph PowerShell SDK 版本

    我發現 Microsoft.Graph 2.6.0 有一些 Bug,如果你已經安裝最新版的話,建議可以先移除所有版本,重新安裝 2.5.0 版本,等未來有新版出來再升級。

    # 先移除 Microsoft.Graph 所有版本
    Uninstall-Module Microsoft.Graph -AllVersions
    
    # 再移除 Microsoft.Graph 所有相依模組 (會移除很久很久)
    Get-InstalledModule Microsoft.Graph.* | ? Name -ne "Microsoft.Graph.Authentication" | Uninstall-Module -AllVersions
    
    # 必須最後才能移除 Microsoft.Graph.Authentication 模組
    Uninstall-Module Microsoft.Graph.Authentication -AllVersions
    
    # 重新安裝較舊的 2.5.0 版本
    Install-Module -Name Microsoft.Graph -Scope CurrentUser -RequiredVersion 2.5.0
    

Microsoft Graph PowerShell 的身分驗證方法 (Authentication)

由於 Microsoft Graph PowerShell SDK 的背後是呼叫 Microsoft Graph REST API,而授權機制主要是走 OAuth 2.0 流程,所以你必須先取得一組 OAuth 2.0 的存取權杖 (Access Token),才能夠透過 PowerShell 來存取 Microsoft Graph REST API。

存取 Microsoft Graph REST API 有支援兩種授權方式:

  1. 委派授權存取 (delegated access)

    這種授權方式是透過使用者的身分來存取 Microsoft Graph REST API,所以在登入的後會需要使用者登入,並先取得使用者的同意,才能夠透過 PowerShell 來存取 Microsoft Graph REST API。

    我們這篇文章主要會講這種驗證授權方式!

  2. 應用程式授權存取 (app-only access)

    這種授權方式是透過應用程式的身分來存取 Microsoft Graph REST API,所以在登入的後會需要應用程式的憑證 (Client Secret),並先取得管理員的同意,才能夠透過 PowerShell 來存取 Microsoft Graph REST API。如果要透過這種方式授權,可以參考 Use app-only authentication with the Microsoft Graph PowerShell SDK 文件。

因為 Microsoft Graph PowerShell SDK 背後是 OAuth 2.0 授權機制,所以我們在發動授權請求時,會需要明確指定 Scope (範圍),好讓我們拿到的 Access Token 可以順利呼叫相對應的 Microsoft Graph REST API。由於 Microsoft Graph PowerShell SDK 的 Cmdlet 太多了,我無法一一列舉有哪些 Scope 可以設定,通常都是要用的時候才去找 Scope 要設定哪些,且 API 文件通常都會標注這類授權範圍資訊!

我以我這次的執行目的來說,我希望可以設定使用者的 M365 授權,而且要透過 Set-MgUserLicense Cmdlet 來指派授權,如果要找出該 Cmdlet 相關的 Scope 有哪些,可以執行以下命令查詢:

Find-MgGraphCommand -command Set-MgUserLicense | Select -First 1 -ExpandProperty Permissions

 Find-MgGraphCommand -command Set-MgUserLicense | Select -First 1 -ExpandProperty Permissions

由於我需要對使用者進行讀寫的操作,所以我選擇 User.ReadWrite.All 範圍,另外我還需要讀取公司的組織資訊,唯讀即可,所以我選擇 Organization.Read.All 範圍,所以我是這樣執行登入的:

$TenantId = '95934928-746e-4154-a060-790e3ef6a623'
Connect-MgGraph -TenantId "$TenantId" -Scopes "User.ReadWrite.All","Organization.Read.All","Team.ReadBasic.All"

使用 Connect-MgGraph Cmdlet 來登入,最重要的就是指定 -Scopes 參數,沒有指定正確的範圍,就無法執行相對應的 REST API。

恭喜你,你已經成功登入 Microsoft Graph 了!接下來就可以開始使用 Microsoft Graph PowerShell 來存取各項服務了!

快速上手 Microsoft Graph PowerShell

以下我就快速介紹幾個常用的 Cmdlet 用法,讓你可以快速上手 Microsoft Graph PowerShell。

  1. 列出公司內的使用者清單

    列出所有使用者

    Get-MgUser
    

    透過 -Filter 參數篩選資料 (語法參見 Filter parameter 文件)

    Get-MgUser -Filter "displayName eq '王大明'"
    
    Get-MgUser -Filter "UserPrincipalName eq 'user@example.com'"
    

    找出沒有指派授權的使用者清單

    Get-MgUser -Filter 'assignedLicenses/$count eq 0' -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All
    
    Get-MgUser -Filter "assignedLicenses/`$count eq 0 and endsWith(UserPrincipalName, '@example.com')" -ConsistencyLevel eventual -CountVariable unlicensedUserCount -All
    

    如果你想查詢更多範例,可以執行以下命令快速查詢:

    Get-Help Get-MgUser -Detailed
    
  2. 列出使用者加入的 Teams (團隊)

    # 先找出其中一位使用者
    $user = Get-MgUser -Filter "UserPrincipalName eq 'user@example.com'"
    
    # 找出該使用者加入的 Teams
    Get-MgUserJoinedTeam -UserId $user.Id
    
  3. 更新使用者授權

    # 取得目前的 M365 授權清單 (Sku)
    Get-MgSubscribedSku -All
    
    # 取得 SPE_E3 授權物件
    $SPEE3Sku = Get-MgSubscribedSku -All | where SkuPartNumber -eq 'SPE_E3'
    
    # 設定授權給使用者 (-UserId)
    Set-MgUserLicense -UserId $UserPrincipalName -AddLicenses @{SkuId = $SPEE3Sku.SkuId} -RemoveLicenses @()
    
    # 查看使用者授權
    Get-MgUserLicenseDetail -UserId 'user@example.com'
    
  4. 查詢有哪些 Cmdlet 命令可用

    找出 Cmdlet 命令中包含 License 字樣的命令

    Find-MgGraphCommand -Command ".*License.*" -APIVersion 'v1.0'
    

    其中 -APIVersion 'v1.0' 代表指列出 v1.0 的 Cmdlet 命令,不顯示 beta 版本的 Cmdlet 命令。

    找出 REST API 的網址中出現過 license 字樣的 Cmdlets

    Find-MgGraphCommand -Uri ".*license.*" -Method 'Get' -ApiVersion 'v1.0'
    

    另一種語法

    Get-Command -Module "Microsoft.Graph*" "*License*"
    
  5. 找出 Cmdlet 與 REST API 的關係

    從 REST API 的 URI 找出哪些 Cmdlet 命令可以用

    Find-MgGraphCommand -Uri '/users/{id}'
    

    從 Cmdlet 找出背後使用了哪些 REST API

    Find-MgGraphCommand -Command 'Get-MgUser'
    
  6. 找出 Cmdlet 所需的 OAuth 權限 (Scope)

    找出特定 Cmdlet 需要哪些 Scope 權限

    Find-MgGraphCommand -command 'Get-MgUser' | Select -First 1 -ExpandProperty Permissions
    

    找出領域(domain)需要哪些 Scope 權限

    Find-MgGraphPermission "application"
    Find-MgGraphPermission "mail"
    Find-MgGraphPermission "teams"
    Find-MgGraphPermission "files"
    

    找出特定領域下特定權限

    Find-MgGraphPermission "mail.send"
    
  7. 取得 Microsoft Graph 的相關資訊

    Get-MgContext
    

    取得目前取得到的 Scope 資訊

    Get-MgContext | Select -ExpandProperty Scopes
    
  8. 透過 Microsoft Graph PowerShell 方便的呼叫 Microsoft Graph REST API

    Invoke-MgGraphRequest -Method GET https://graph.microsoft.com/v1.0/me
    
  9. 登出 Microsoft Graph PowerShell

    Disconnect-MgGraph
    

總結

透過這篇文章的整理,我算是可以深入的理解 Microsoft Graph PowerShell 的基本使用方法了,以後要找命令來執行就比較不會像個無頭蒼蠅一樣亂找。

Microsoft Graph PowerShell 說白了背後就是使用 Microsoft Graph 提供的所有 REST API 來執行,這也是微軟 M365 最核心的東西,未來所有 M365 的自動化都會以 Microsoft Graph 為主,所以要學會這些觀念與知識應該是遲早的事。

最後,由於 Microsoft Graph 與 OAuth 綁定的很深,如果對 OAuth 沒有一定程度的理解,對授權這部分的邏輯也會不容易掌握,所以我建議你可以先去學習一下 OAuth 的基本觀念,這樣對於 Microsoft Graph PowerShell 的使用會更有幫助。

相關連結

留言評論