# 如何將 AzureAD 與 MSOnline 模組改用 Microsoft Graph PowerShell 執行

我之前一直使用 PowerShell 的 [MSOnline V1](https://learn.microsoft.com/en-us/powershell/microsoftgraph/migration-steps) 與 [AzureAD V2](https://learn.microsoft.com/en-us/powershell/azure/active-directory/overview?view=azureadps-2.0&preserve_view=true&WT.mc_id=DT-MVP-4015686) 模組在做許多 Microsoft 365 的自動化工作，原本微軟就[打算在 2023 年 9 月 30 日之前棄用這兩個模組](https://techcommunity.microsoft.com/t5/microsoft-entra-blog/important-azure-ad-graph-retirement-and-powershell-module/ba-p/3848270?WT.mc_id=DT-MVP-4015686)，但因故延期到 2024 年 3 月 30 日，也就是這個月底。在死線之前，我終於騰出時間把我過往的 Microsoft 365 自動化腳本全面升級到 Microsoft Graph PowerShell 模組，這個過程真的不太輕鬆，改變真的蠻大的。

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/da99be1eb5ad339b2bd7-c74039c9-4f34-4e76-9d84-e708adffd88c.webp)

### 從 New-MsolUser 轉換到 New-MgUser

我之前最常用來建立帳號的腳本如下：

```powershell
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
```

> 上述腳本是我在寫 [如何透過 Microsoft Graph PowerShell 設定使用者的 M365 授權](/post/2023/09/20/Microsoft-Graph-PowerShell-Set-M365-License-Sku) 這篇文章時調整過的版本，建立帳號不只有這一個命令，還要有授權動作才完整，詳細說明請見我這篇文章。

我利用官方整理的 [cmdlet map](https://learn.microsoft.com/en-us/powershell/microsoftgraph/azuread-msoline-cmdlet-map) 對應表，發現 `New-MsolUser` 指令對應到 [`New-MgUser`](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.users/new-mguser?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686) 指令，所以我將這個網頁打開，然後一一對應參數，修改我的腳本，重點是：

1.  這個 [New-MgUser](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.users/new-mguser?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686) 網頁超級大，好幾萬字，光是 HTML 就將近 1MB 之多，是我有史以來見過最複雜的單一 Cmdlet 文件。其中最扯的是，我用 Google Chrome 開啟這個網頁後，竟然整台主機都卡頓了起來，這真的是太誇張了。
2.  從 `New-MsolUser` 到 `New-MgUser` 許多參數都改名了，而且沒有提供對應表，因為這個 `New-MgUser` 真的太複雜，大概沒人會花心思去做對照表，明明參數不多，但我一個一個比對也要花上半小時才能全部比對到。

以下就是我逐一比對後的成果：

```powershell
New-MgUser `
    -UserPrincipalName $UserPrincipalName `
    -DisplayName $DisplayName -GivenName $FirstName -Surname $LastName `
    -UsageLocation $UsageLocation `
    -MobilePhone $MobilePhone `
    -OfficeLocation $Office -BusinessPhones $PhoneNumber `
    -PreferredLanguage $PreferredLanguage `
    -State $State `
    -StreetAddress $StreetAddress `
    -JobTitle $Title -OtherMails $AlternateEmailAddresses `
    -Country $Country `
    -PostalCode $PostalCode `
    -City $City `
    -Department $Department `
    -FaxNumber $Fax
```

![New-MsolUser to New-MgUser migration.ps1](https://stwillblogassets.blob.core.windows.net/files/images/external/github.com/7a30e941743343432b0b-590f78a3-aa7d-4f03-9502-420473c9c39d.jpg)

然而，上述命令並不完整，還需要額外加上 3 個參數才行：

1.  加入 `-MailNickName` 指定未來 Exchange Online 信箱的主要別名
2.  加入 `-AccountEnabled` 才能讓帳號建立後自動為「啟用」狀態 (預設為不啟用)
3.  加入 `-PasswordProfile` 設定預設密碼以及是否要求在首次登入變更密碼

所以完整版命令如下：

```powershell
$PasswordProfile = @{
    Password = $PlainPassword
    ForceChangePasswordNextSignIn = $true
}

New-MgUser `
    -UserPrincipalName $UserPrincipalName `
    -DisplayName $DisplayName -GivenName $FirstName -Surname $LastName `
    -UsageLocation $UsageLocation `
    -MobilePhone $MobilePhone `
    -OfficeLocation $Office -BusinessPhones $PhoneNumber `
    -PreferredLanguage $PreferredLanguage `
    -State $State `
    -StreetAddress $StreetAddress `
    -JobTitle $Title -OtherMails $AlternateEmailAddresses `
    -Country $Country `
    -PostalCode $PostalCode `
    -City $City `
    -Department $Department `
    -FaxNumber $Fax `
    -MailNickName $UserName `
    -PasswordProfile $PasswordProfile `
    -AccountEnabled
```

### 強制登出所有裝置

-   舊版語法 ([Get-AzureADUser](https://learn.microsoft.com/zh-tw/powershell/module/azuread/get-azureaduser?view=azureadps-2.0&WT.mc_id=DT-MVP-4015686))
    
    ```powershell
    Get-AzureADUser -SearchString $UserPrincipalName  | Revoke-AzureADUserAllRefreshToken
    ```
    
-   新版語法 ([Revoke-MgUserSignInSession](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.users.actions/revoke-mgusersigninsession?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686))
    
    ```powershell
    Revoke-MgUserSignInSession -UserId $UserPrincipalName
    ```
    

### 停用 Per-user MFA 的方法

-   舊版語法 ([Set-MsolUser](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.users/update-mguser))
    
    ```powershell
    Set-MsolUser -UserPrincipalName $UserPrincipalName -StrongAuthenticationRequirements @()
    ```
    
-   新版語法
    
    ```powershell
    無
    ```
    
    我唯一能找到的[討論串](https://learn.microsoft.com/en-us/answers/questions/1144760/functionality-for-enabling-enforcing-disabling-per?WT.mc_id=DT-MVP-4015686)，答案是「**否定的**」，也就是說目前沒有辦法透過 Microsoft Graph PowerShell 做到這件事情，只能用 `MSOnline` 模組的 Cmdlet 才能做到。
    
    > 等待大神回答: [How to disable per-user MFA settings using Microsoft Graph PowerShell?](https://stackoverflow.com/q/78096777/910074)
    
    雖然找不到停用的方法，但我倒是有找到可以取得使用者透過手機認證的資訊，這應該跟 MFA 有直接相關：
    
    ```powershell
    Get-MgUserAuthenticationPhoneMethod -UserId $UserPrincipalName -PhoneAuthenticationMethodId '3179e48a-750b-4051-897c-87b9720928f7'
    ```
    
    > 這裡的 Magic Number `3179e48a-750b-4051-897c-87b9720928f7` 其實可以從 [Get phoneAuthenticationMethod](https://learn.microsoft.com/en-us/graph/api/phoneauthenticationmethod-get?view=graph-rest-1.0&tabs=http&WT.mc_id=DT-MVP-4015686#http-request) 文件找到 3 個可用的 Id:
    
    -   `3179e48a-750b-4051-897c-87b9720928f7` 用來取得 `mobile` 電話類型
        
    -   `b6332ec1-7057-4abe-9331-3d72feddfe41` 用來取得 `alternateMobile` 電話類型
        
    -   `e37fc753-ff3b-4958-9484-eaa9425c82bc` 用來取得 `office` 電話類型
        
        ```powershell
        Get-MgUser -All:$true -PipelineVariable user | ForEach-Object {
            Get-MgUserAuthenticationPhoneMethod -UserId $user.UserPrincipalName |
                Select-Object @{ N='UserPrincipalName'; E={ $user.UserPrincipalName }}, ID, PhoneNumber, PhoneType
        }
        ```
        

### 變更密碼

-   舊版語法 ([Set-MsolUserPassword](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.signins/reset-mguserauthenticationmethodpassword))
    
    ```powershell
    Set-MsolUserPassword -UserPrincipalName $UserPrincipalName `
      -NewPassword $PlainPassword -ForceChangePassword $true
    ```
    
-   新版語法 ([Reset-MgUserAuthenticationMethodPassword](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.signins/reset-mguserauthenticationmethodpassword))
    
    ```powershell
    Reset-MgUserAuthenticationMethodPassword `
      -UserId $UserPrincipalName -NewPassword $PlainPassword `
      -AuthenticationMethodId '28c10230-6103-485e-b985-444c60001490'
    ```
    
    > 這裡的 Magic Number `28c10230-6103-485e-b985-444c60001490` 其實可以從 [Manage users' authentication methods using Microsoft Graph](https://learn.microsoft.com/en-us/graph/authenticationmethods-get-started?tabs=http#response) 文件找到，這是在 Microsoft Entra ID 中所有密碼認證方式的 GUID。
    

### 從某個群組移除成員

-   舊版語法 ([Remove-AzureADGroupMember](https://learn.microsoft.com/en-us/powershell/module/azuread/remove-azureadgroupmember?view=azureadps-2.0&WT.mc_id=DT-MVP-4015686))
    
    ```powershell
    $AADGroup = Get-AzureADGroup -Filter "DisplayName eq '$GroupName'"
    $AADUser  = Get-AzureADUser -Filter "UserPrincipalName eq '$UserPrincipalName'"
    Remove-AzureADGroupMember -ObjectId $AADGroup.ObjectID  -MemberId $AADUser.ObjectID
    ```
    
-   新版語法 ([Remove-MgGroupMemberByRef](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.groups/remove-mggroupmemberbyref?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686))
    
    ```powershell
    $MgGroup = Get-MgGroup -Filter "DisplayName eq '$GroupName'"
    $MgUser  = Get-MgUser -UserId $UserPrincipalName
    Remove-MgGroupMemberByRef -GroupId $MgGroup.Id -DirectoryObjectId $MgUser.Id
    ```
    

### 總結

這個改變真的不小，去年我在修復無法執行的自動化腳本時，就覺得這不會是一件輕鬆的工作，所以一直拖到現在才開始動手，還好有摸索出脈絡，現在改起來不會覺得太困難了，但還是要花上不少時間查找資料，許多物件架構都變了。

最後我整理幾個不錯的連結，供大家參考：

1.  [Find Azure AD PowerShell and MSOnline cmdlets in Microsoft Graph PowerShell](https://learn.microsoft.com/en-us/powershell/microsoftgraph/azuread-msoline-cmdlet-map?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686)
    
    幫你快速找出在 `Azure AD PowerShell` 與 `MSOnline cmdlets` 常用的 Cmdlet 與 `Microsoft Graph PowerShell` 對應的命令！
    
2.  [Azure AD PowerShell to Microsoft Graph PowerShell migration FAQ](https://learn.microsoft.com/en-us/powershell/azure/active-directory/migration-faq?view=azureadps-2.0&WT.mc_id=DT-MVP-4015686)
    
    關於遷移到 Microsoft Graph PowerShell 的常見問題解答。
    
3.  [Microsoft Graph REST API v1.0 endpoint reference](https://learn.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0&preserve-view=true&WT.mc_id=DT-MVP-4015686)
    
    許多 Microsoft Graph PowerShell 文件沒寫的技術細節，都可以在 Microsoft Graph API 的文件中找到，所以非常重要！
    

### 相關連結

-   [Azure AD PowerShell to Microsoft Graph PowerShell migration FAQ | Microsoft Learn](https://learn.microsoft.com/en-us/powershell/azure/active-directory/migration-faq?view=azureadps-2.0&WT.mc_id=DT-MVP-4015686)
-   [Find Azure AD and MSOnline cmdlets in Microsoft Graph PowerShell | Microsoft Learn](https://learn.microsoft.com/en-us/powershell/microsoftgraph/azuread-msoline-cmdlet-map?view=graph-powershell-1.0&WT.mc_id=DT-MVP-4015686)
-   [Functionality for Enabling/Enforcing/Disabling Per-User MFA in Microsoft Graph](https://learn.microsoft.com/en-us/answers/questions/1144760/functionality-for-enabling-enforcing-disabling-per?WT.mc_id=DT-MVP-4015686)
-   相關文章
    -   [如何透過 Microsoft Graph PowerShell 設定使用者的 M365 授權](/post/2023/09/20/Microsoft-Graph-PowerShell-Set-M365-License-Sku)
