GIGA スクール年度更新ハンドブック | Microsoft 365 (2023年度版)　第1.0版

# はじめに

本書は[「GIGAスクール年度更新ハンドブック | Microsoft 365 第2.3版」](https://qiita.com/hisaho/items/403bb87c2ed0dbf27727)の2023年度改訂版となります。

# 変更点

[「GIGAスクール年度更新ハンドブック | Microsoft 365 第2.3版」](https://qiita.com/hisaho/items/403bb87c2ed0dbf27727)では、MS Online PowerShell を使ったアカウントメンテナンス(登録、更新、削除)方法を紹介しました。MS Online PowerShell は2023年3月31日に MSOnline PowerShell を使ったライセンス割り当ての機能の提供が終了し、さらに2023年6月30日にMSOnline PowerShell が廃止されます。そのため、今後 PowerShell を使用してアカウントメンテナンスを行う場合は Microsoft Graph PowerShell を使用する必要があります。本書ではMicrosoft Graph PowerShell を使用してアカウント管理について説明していきます。

MSOnline PowerShell から Microsoft Graph PowerShell への移行についての詳細は、Microsoft の公式ドキュメント[「Azure AD PowerShell から Microsoft Graph PowerShell への移行に関する FAQ」](https://learn.microsoft.com/ja-jp/powershell/azure/active-directory/migration-faq?view=azureadps-2.0)をご参照ください。

# Microsoft Graph PowerShell SDK をインストールする

まずはじめに Microsoft Graph PowerShell を使用るために　Microsoft Graph PowerShell  をインストールします。
Microsoft Graph PowerShell をインストールために PowerShell を管理者として起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/14181ad9-4151-e3c4-762b-2df6b20ecdcd.png)
PowerShellが起動したら、以下のコマンドレットを実行して Microsoft Graph PowerShell SDK をインストールします。
```PowerShell
> Install-Module Microsoft.Graph
```
初期設定ですとPSGallery が信頼されていないリポジトリとして設定されており、以下のような警告が表示されます。

```PowerShell
> Install-Module Microsoft.Graph
信頼されていないリポジトリ
信頼されていないリポジトリからモジュールをインストールしようとしています。このリポジトリを信頼する場合は、Set-PSRepository コマンドレットを実行して、リポジトリの InstallationPolicy
の値を変更してください。'https://www.powershellgallery.com/api/v2/' からモジュールをインストールしますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"):
```
[Y] を入力すれば Microsoft Graph PowerShell SDK はインストールされますが「PSGallery はある程度信頼できるだろう」と判断した場合にはこの警告を表示しないようにすることもできます。 Set-PSRepository を利用して PSGallery を信頼できるリポジトリとして設定することによって PSGallery にある様々なモジュールを警告無しにインストールできるようになります。
PSGallery の信頼するリポジトリーに変更する方法は以下の通りです。

```PowerShell
# 設定値の確認
> Get-PSRepository
Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
PSGallery                 Untrusted            https://www.powershellgallery.com/api/v2/

# PSGallery を信頼できるリポジトリに変更
> Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

# 設定値の確認
> Get-PSRepository
Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
PSGallery                 Trusted              https://www.powershellgallery.com/api/v2/
```
# PowerShell を実行できるようにする
クライアント版 Windows の PowerShell は、標準設定ではスクリプト（拡張子 .ps1 のファイル）の実行が制限されています。これは、マルウェアなどの危険なスクリプトの不用意な実行を防ぐというセキュリティ上の配慮によるものです。自分で作成したスクリプトを実行するには事前に実行ポリシーを変更する必要があります。

実行ポリシーは、Set-ExecutionPolicy コマンドレット（または PowerShell コマンドの -ExecutionPolicy パラメータ）を用いて変更します。下記のコマンドを実行することで以下の PowerShell を実行することができるようになります。

```PowerShell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
```

# Microsoft 365 のライセンスを確認する

MSOnline PowerShell では、Get-MsolAccountSku コマンドレットを使用することで、そのテナントで使用可能なライセンスを調べることができました。Microsoft Graph PoweShell では Get-MgSubscribedSku コマンドレットを使用して　SkuId　を取得します。
まずはじめに Get-MgSubscribedSku コマンドレットを使って Microsoft 365 に接続します。

```PowerShell
Connect-MgGraph -Scopes "Organization.Read.All","User.ReadWrite.All"
```
ユーザー認証の画面が表示されますので、IDとパスワード(多様性認証をONにしている場合には多要素認証)を入力します。
サインインができたら以下のコマンドレッドでモジュールを読み込みます。

```PowerShell
Import-Module -Name Microsoft.Graph.Users
```
モジュールの読み込みが完了したら Get-MgSubscribedSku コマンドレッドを実行してこのテナントで利用できるライセンスのSkuIdを取得します。

```PowerShell
Get-MgSubscribedSku | ft SkuId, SkuPartNumber -Wrap
```
このように SkuId と SkuPartNumber が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/4e6f1e58-4a72-08b6-0680-64ecfe60beef.png)

ユーザーにライセンスを割り当てる際には SkuId が必要になりますので、メモしておいてください。上記の例ですと SubParNumber に表示された STANDARDWOFFPACK_STUDENT が児童生徒用の Office 365 A1 ライセンス、STANDARDWOFFPACK_FACULTY が 教職員用の Office 365 A1 ライセンス、M365_EDU_GIGA_PROMO が GIGA PROMO 用のライセンスになります。

# アカウントの登録

## アカウント登録用のCSVファイルの作成

アカウント登録用のCSVファイルの[**サンプルファイル**](https://1drv.ms/u/s!AkVwRd2ThNyEiJZBKJw1qJXZcQUH3w?e=IvZDt1)をダウンロードしてください。
2行目以降に必要なデータを入力します。アカウント登録する際に最低限必要な属性値は、UserPrincipalName, DisplayName, Password です。ユーザーに割り当てるライセンスはO列からQ列に記入してください。このドキュメントで提示するサンプルコードでは最大3種類のライセンスまで割り当てできるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/9504de18-484a-bf1f-1e41-cfd4cc2ba32b.png)


## アカウント登録用のPowerShellスクリプトの作成

以下にアカウント登録用のPowerShellを示します。メモ帳などにコピーして、addm365user.ps1といったファイル名で保存してください。
このスクリプトでは、パスワードの有効期限を無期限にする (-PasswordPolicies  "DisablePasswordExpiration,DisableStrongPassword")、初回ログイン時にパスワードの変更を要求しない ("forceChangePasswordNextSignIn" = $false)　ように設定してます。

```PowerShell:addm365user.ps1
###############################################################################################################################
# Name
#     addm365user.ps1 - Microsoft 365 にアカウントを追加する
# SYNOPSIS
#     addm365user [INPORT FILE]
# DESCRIPTION
#     Microsoft 365 のアカウント作成用の[INPORT FILE]を読み込み、Microsoft 365 にアカウントを登録、
#     ライセンス付与をし、AddedNewUsers-YYYY_MM_DD-HH_MM.csv に登録結果を出力します。
#     このスクリプトでは弱いパスワードも登録可能で、有効期限もなしになっています。また初期サイン時にパスワード変更も求められません。
#     CSVの書式は1行目にタイトル、2行目以降に登録データを入力します。
#     1行目: UserPrincipalName,Password,MailNickname,DisplayName,GivenName,SurName,JobTitle,EmployeeId,EmployeeType,Department,City,State,Country,StreetAddress,PostalCode,SkuId1,SkuId2,SkuId3
#     SkuId1～3 には、Get-MgSubscribedSku | ft SkuId, SkuPartNumber -Wrap　で取得した SkuId を入力してください。
###############################################################################################################################
Connect-MgGraph -Scopes "User.ReadWrite.All" > $null
Import-Module -Name Microsoft.Graph.Users


date
echo "  Create new users"

$addedtime = Get-Date -format "yyyy_MM_dd-HH_mm"
$outputfilename = "AddedNewUsers-" + $addedtime + ".csv"

Import-Csv -Path $Args[0] -Encoding UTF8 | `
foreach {
    $UserPrincipalName =  $_.UserPrincipalName
    $DisplayName = $_.DisplayName
    $MailNickName = $UserPrincipalName.Split("@")[0]
    $SurName = $_.SurName
    $GivenName = $_.GivenName
    $JobTitle = $_.JobTitle ; if([string]::IsNullOrEmpty($JobTitle)){$JobTitle = " "}
    $EmployeeId = $_.EmployeeId ; if([string]::IsNullOrEmpty($EmployeeId)){$EmployeeId = " "}
    $EmployeeType = $_.EmployeeType ; if([string]::IsNullOrEmpty($EmployeeType)){$EmployeeType = " "}
    $Department = $_.Department ;  if([string]::IsNullOrEmpty($Department)){$Department = " "}
    $City = $_.City ; if([string]::IsNullOrEmpty($City)){$City = " "}
    $State = $_.State ; if([string]::IsNullOrEmpty($State)){$State = " "}
    $Country = $_.Country ; if([string]::IsNullOrEmpty($Country)){$Country = " "}
    $PostalCode = $_.$PostalCode ; if([string]::IsNullOrEmpty($PostalCode)){$PostalCode = " "}
    $StreetAddress = $_.$StreetAddress ; if([string]::IsNullOrEmpty($StreetAddress)){$StreetAddress = " "}

    If([string]::IsNullOrEmpty($GivenName) -or [string]::IsNullOrEmpty($SurName)) {
        New-MgUser -AccountEnabled -UserPrincipalName "$UserPrincipalName" -DisplayName "$DisplayName" -MailNickName "$MailNickname" -UsageLocation "JP" -JobTitle "$JobTitle" -EmployeeId "$EmployeeId" -EmployeeType "$EmployeeType" -Department  "$Department" -City "$City" -State "$State" -Country "$Country" -PostalCode "$PostalCode" -StreetAddress "$StreetAddress" -PasswordPolicies  "DisablePasswordExpiration,DisableStrongPassword" -PasswordProfile @{ "Password"=$_.Password ; "forceChangePasswordNextSignIn" = $false}
    } 
    Else {
        New-MgUser -AccountEnabled -UserPrincipalName "$UserPrincipalName" -DisplayName "$DisplayName" -MailNickName "$MailNickname" -SurName "$SurName" -GivenName "$GivenName" -UsageLocation "JP" -JobTitle "$JobTitle" -EmployeeId "$EmployeeId" -EmployeeType "$EmployeeType" -Department  "$Department" -City "$City" -State "$State" -Country "$Country" -PostalCode "$PostalCode" -StreetAddress "$StreetAddress" -PasswordPolicies  "DisablePasswordExpiration,DisableStrongPassword" -PasswordProfile @{ "Password"=$_.Password ; "forceChangePasswordNextSignIn" = $false} 
    }
} | Select-Object Id, UserPrincipalName, DisplayName, GivenName, Surname, JobTitle, EmployeeId, EmployeeType, Department, City, State, Country, StreetAddress, PostalCode | Export-Csv -Path $outputfilename -Encoding UTF8

date
echo "  Licensing to users"
Import-Csv -Path $Args[0] -Encoding UTF8 | `
foreach {
    $SkuId1 = $_.SkuId1
    $License1 = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphAssignedLicense -Property @{SkuId = $SkuId1}
    $SkuId2 = $_.SkuId2
    $License2 = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphAssignedLicense -Property @{SkuId = $SkuId2}
    $SkuId3 = $_.SkuId3
    $License3 = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphAssignedLicense -Property @{SkuId = $SkuId3}
    if([string]::IsNullOrEmpty($SkuId2)){
        $License1 = New-Object -TypeName Microsoft.Graph.PowerShell.Models.MicrosoftGraphAssignedLicense -Property @{SkuId = $SkuId1}
        Set-MgUserLicense -UserId $_.UserPrincipalName -AddLicenses @($License1) -RemoveLicenses @() > $null
        }
        elseif([string]::IsNullOrEmpty($SkuId3)){
            Set-MgUserLicense -UserId $_.UserPrincipalName -AddLicenses @($License1, $License2) -RemoveLicenses @() > $null
        }
        else {
            Set-MgUserLicense -UserId $_.UserPrincipalName -AddLicenses @($License1, $License2, $License3) -RemoveLicenses @() > $null
        }
} 
Disconnect-MgGraph > $null
date
echo "  Completed"

```

## アカウントの登録

addm365user.ps1 を実行して新規アカウントを登録します。入力ファイルには「アカウントう登録用のCSVファイル」で作成したファイルを使用してください。

```PowerShell
addm365user.ps1 <入力ファイル名> 
```

addm365user.ps1 を実行しますと、カレントディレクトリに AddedNewUsers-YYYY_MM_DD-HH_MM.csv ファイルが作成され、新しく登録されたユーザーの情報が保存されます。

# すでに登録済みのユーザーを取得する

すでに登録されているユーザーリストの一覧を取得するスクリプト(getm365user.ps1)を以下に示します。
このスクリプトを実行するとカレントディレクトリに RegisteredUsers-YYYY_MM_DD-HH_MM.csv ファイルが作成され、すでに登録されているユーザー情報が保存されます。

```PowerShell:getm365user.ps1
###############################################################################################################################
# Name
#  get365user.ps1 - Microsoft 365 に登録されているアカウントを取得する
# SYNOPSIS
#     getm3365user
# DESCRIPTION
#     Microsoft 365 に登録されているユーザーを取得して、RegisteredUsers_YYYY_MM_DD-HH_MM.csv に出力します。
###############################################################################################################################

Connect-MgGraph -Scopes "User.ReadWrite.All" > $null
Import-Module -Name Microsoft.Graph.Users

date
echo "  Get All users"
$addedtime = Get-Date -format "yyyy_MM_dd-HH_mm"
$outputfilename = "RegisteredUsers-" + $addedtime + ".csv"

Get-MgUser -All | Select-Object Id, UserPrincipalName, DisplayName, GivenName, Surname, JobTitle, EmployeeId, EmployeeType, Department, City, State, Country, StreetAddress, PostalCode | Export-Csv -Path $outputfilename -Encoding UTF8
date
echo "  Completed"
```

# ユーザーを削除する

## ユーザー削除リストの作成

削除したいユーザーリストを作成します。1行目にUserPrincipalNameと入力し、2行目以降に削除したいUserPrincipalNameを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/83bcacf3-4747-bb15-6179-3c674809d318.png)

## ユーザー削除用の PowerShell

```PowerShell:rmm365user.ps1
###############################################################################################################################
# Name
#  rmm365user.ps1 - Microsoft 365 のアカウント削除する
# SYNOPSIS
#     rmm3365user [INPORT FILE]
# DESCRIPTION
#     [INPORT FILE] を読み込み、Microsoft 365 のアカウントを削除します。
#     削除したアカウントはゴミ箱に入り、30日後に自動的に完全削除されます。
#     30日以内にゴミ箱にいるユーザーを削除する場合には、rmm365deletedusers.ps1 コマンドを利用します。
#     削除用の [INPORT FILE]　は、
#     一行目: UserPrincilaName 2行目以降に削除するユーザー情報（UserPrincipalName）を入力してください。
###############################################################################################################################

Connect-MgGraph -Scopes "User.ReadWrite.All"
Import-Module -Name Microsoft.Graph.Users

date
echo "  Remove users"

Import-Csv -Path $Args[0] | foreach {Remove-MgUser -UserId $_.UserPrincipalName -PassThru} 

Disconnect-MgGraph > $null

date
echo "  Completed"
```

## ユーザーの削除

ユーザーを削除するには以下のコマンドレッドを実行します。
```PowerShell
rmm365user <入力ファイル名>
```

削除されたユーザーはゴミ箱に入り、30日後に自動削除されます。

# ゴミ箱にいるユーザーを完全削除する

# ゴミ箱にいるユーザー削除リストの作成

Microsoft 365 管理センターから削除済みのユーザーリストを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/a842dc37-9c6b-fee8-ee47-9b30234d1c74.png)

出力されたファイルを開き「オブジェクトId」→「ObjectId」に書き換えて保存します。


# ゴミ箱のユーザー削除用の PowerShell

```PowerShell: rmm365deleteduser.ps1
###############################################################################################################################
# Name
#  rmm365deleteduser.ps1 - Microsoft 365 のアカウント削除する
# SYNOPSIS
#     rmm3365deleteduser [INPORT FILE]
# DESCRIPTION
#     [INPORT FILE] を読み込み、ゴミ箱にいるMicrosoft 365 のアカウントを削除します。、
#     一行目: Id 2行目以降に削除するユーザー情報(OObject Id）を入力してください。
###############################################################################################################################

Connect-MgGraph -Scopes "User.ReadWrite.All" > $null
Import-Module -Name Microsoft.Graph.Users

date
echo "  Remove deleted users"

Import-Csv -Path $Args[0] -Encoding UTF8 | foreach {Remove-MgDirectoryDeletedItem -DirectoryObjectId $_.Id}

Disconnect-MgGraph > $null

date
echo "  Completed"
```
# ゴミ箱にいるユーザーの削除

ゴミ箱にいるユーザーには以下のコマンドを実行します。
```PowerShell
rmm365deleteduser <入力ファイル>
```