PowerShell и Microsoft Graph API: автоматизация Microsoft 365

Что такое Microsoft Graph API

Microsoft Graph — единая точка входа для всех сервисов Microsoft 365: Azure AD, Exchange Online, SharePoint, Teams, OneDrive, Intune. Вместо десятка разных модулей PowerShell (MSOnline, AzureAD, ExchangeOnlineManagement) можно использовать один универсальный SDK.

Преимущества Microsoft Graph перед устаревшими модулями:

  • Единый API — один модуль для всех сервисов M365
  • Активная разработка — модули MSOnline и AzureAD объявлены deprecated
  • Гранулярные разрешения — можно запросить только нужные права
  • REST API — можно вызывать напрямую через Invoke-RestMethod
  • Поддержка приложений — автоматизация без интерактивного входа

Установите модуль Microsoft Graph PowerShell SDK:

Install-Module Microsoft.Graph -Scope CurrentUser

# Или установите только нужные подмодули
Install-Module Microsoft.Graph.Users
Install-Module Microsoft.Graph.Groups
Install-Module Microsoft.Graph.Mail
Install-Module Microsoft.Graph.Teams

Аутентификация в Microsoft Graph

Graph API поддерживает два режима аутентификации: делегированный (от имени пользователя) и серверный (от имени приложения).

Интерактивная аутентификация (для ручных скриптов):

Connect-MgGraph -Scopes "User.Read.All","Group.ReadWrite.All","Mail.Send"

# Проверка подключения
Get-MgContext | Format-List Account, TenantId, Scopes

Аутентификация приложения (для автоматизации без участия пользователя):

  1. Зарегистрируйте приложение в Azure AD → App registrations
  2. Создайте Client Secret или загрузите сертификат
  3. Назначьте Application permissions (не Delegated)
  4. Подтвердите Admin consent
$TenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$ClientSecret = ConvertTo-SecureString "секрет" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($ClientId, $ClientSecret)

Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $Credential

Аутентификация по сертификату

Сертификат безопаснее Client Secret — его нельзя перехватить из логов:

# Создание самоподписанного сертификата
$Cert = New-SelfSignedCertificate -Subject "CN=GraphApp" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeyExportPolicy Exportable `
    -KeySpec Signature `
    -NotAfter (Get-Date).AddYears(2)

# Экспорт публичного ключа для загрузки в Azure AD
Export-Certificate -Cert $Cert -FilePath "C:\GraphApp.cer"

# Подключение по отпечатку сертификата
Connect-MgGraph -TenantId $TenantId `
    -ClientId $ClientId `
    -CertificateThumbprint $Cert.Thumbprint

Загрузите файл GraphApp.cer в Azure AD → App registrations → Certificates & secrets → Upload certificate.

Управление пользователями

Основные операции с пользователями Azure AD через Graph:

# Получить всех пользователей
$Users = Get-MgUser -All -Property DisplayName, Mail, UserPrincipalName, AccountEnabled
$Users | Format-Table DisplayName, Mail, AccountEnabled

# Найти пользователя
$User = Get-MgUser -Filter "userPrincipalName eq 'ivanov@company.ru'"

# Создать нового пользователя
$PasswordProfile = @{
    Password = "TempP@ss2024!"
    ForceChangePasswordNextSignIn = $true
}

New-MgUser -DisplayName "Петров Иван" `
    -UserPrincipalName "petrov@company.ru" `
    -MailNickname "petrov" `
    -PasswordProfile $PasswordProfile `
    -AccountEnabled:$true `
    -UsageLocation "RU" `
    -Department "IT" `
    -JobTitle "Системный администратор"

Массовое обновление пользователей из CSV:

Import-Csv "C:\users-update.csv" -Encoding UTF8 | ForEach-Object {
    Update-MgUser -UserId $_.UPN `
        -Department $_.Department `
        -JobTitle $_.JobTitle `
        -OfficeLocation $_.Office
    Write-Host "Обновлён: $($_.UPN)"
}

Управление группами и членством

Работа с группами безопасности и Microsoft 365:

# Создание группы безопасности
New-MgGroup -DisplayName "IT-Admins" `
    -MailEnabled:$false `
    -MailNickname "it-admins" `
    -SecurityEnabled:$true `
    -Description "Группа ИТ-администраторов"

# Создание группы Microsoft 365 (с почтой и SharePoint)
New-MgGroup -DisplayName "Проект Альфа" `
    -MailEnabled:$true `
    -MailNickname "project-alpha" `
    -SecurityEnabled:$false `
    -GroupTypes @("Unified") `
    -Description "Рабочая группа проекта"

# Добавление участников
$GroupId = (Get-MgGroup -Filter "displayName eq 'IT-Admins'").Id
$UserId = (Get-MgUser -Filter "userPrincipalName eq 'ivanov@company.ru'").Id

New-MgGroupMember -GroupId $GroupId `
    -DirectoryObjectId $UserId

Аудит членства в группах:

# Все участники группы с должностями
Get-MgGroupMember -GroupId $GroupId -All | ForEach-Object {
    $User = Get-MgUser -UserId $_.Id -Property DisplayName, JobTitle, Department
    [PSCustomObject]@{
        Name       = $User.DisplayName
        Title      = $User.JobTitle
        Department = $User.Department
    }
} | Format-Table

Работа с почтой Exchange Online

Microsoft Graph заменяет модуль ExchangeOnlineManagement для базовых операций с почтой:

# Отправка письма от имени пользователя (delegated permission)
$Message = @{
    Subject = "Отчёт за неделю"
    Body = @{
        ContentType = "HTML"
        Content = "<h2>Еженедельный отчёт</h2><p>Все системы работают штатно.</p>"
    }
    ToRecipients = @(
        @{ EmailAddress = @{ Address = "director@company.ru" } }
    )
}

Send-MgUserMail -UserId "admin@company.ru" -Message $Message

# Чтение почтового ящика
$Messages = Get-MgUserMessage -UserId "admin@company.ru" -Top 10 `
    -OrderBy "receivedDateTime desc" `
    -Property Subject, From, ReceivedDateTime

$Messages | Format-Table Subject, @{N='From';E={$_.From.EmailAddress.Address}}, ReceivedDateTime

Для серверных сценариев (Application permission: Mail.Send) используйте -UserId для отправки от имени любого ящика без интерактивной аутентификации.

Создание правил почтового ящика

Автоматизация создания правил для новых сотрудников:

# Создание правила перенаправления
$Rule = @{
    DisplayName = "Пересылка уведомлений"
    Sequence = 1
    IsEnabled = $true
    Conditions = @{
        SubjectContains = @("[ALERT]", "[URGENT]")
    }
    Actions = @{
        ForwardTo = @(
            @{ EmailAddress = @{ Address = "sms-gateway@company.ru" } }
        )
    }
}

New-MgUserMailFolderMessageRule -UserId "admin@company.ru" `
    -MailFolderId "inbox" -BodyParameter $Rule

Управление лицензиями

Автоматизация назначения и отзыва лицензий M365:

# Получить доступные лицензии (SKU)
Get-MgSubscribedSku | Format-Table SkuPartNumber, `
    @{N='Total';E={$_.PrepaidUnits.Enabled}}, `
    @{N='Used';E={$_.ConsumedUnits}}, `
    @{N='Free';E={$_.PrepaidUnits.Enabled - $_.ConsumedUnits}}

# Назначить лицензию пользователю
$SkuId = (Get-MgSubscribedSku | Where-Object SkuPartNumber -eq "O365_BUSINESS_PREMIUM").SkuId

Set-MgUserLicense -UserId "petrov@company.ru" `
    -AddLicenses @(@{SkuId = $SkuId}) `
    -RemoveLicenses @()

# Массовое назначение из группы AD
$GroupMembers = Get-MgGroupMember -GroupId $GroupId -All
foreach ($Member in $GroupMembers) {
    $CurrentLicenses = (Get-MgUserLicenseDetail -UserId $Member.Id).SkuId
    if ($SkuId -notin $CurrentLicenses) {
        Set-MgUserLicense -UserId $Member.Id `
            -AddLicenses @(@{SkuId = $SkuId}) `
            -RemoveLicenses @()
        Write-Host "Лицензия назначена: $($Member.Id)"
    }
}

Для группового назначения лицензий (Group-based licensing) удобнее настроить автоматическое назначение через Azure AD группы в портале Azure.

Отчёты и аналитика

Graph API предоставляет богатые отчёты по использованию M365:

# Отчёт о входах пользователей (требует AuditLog.Read.All)
$SignIns = Get-MgAuditLogSignIn -Top 100 -Filter "status/errorCode ne 0" `
    -OrderBy "createdDateTime desc"

$SignIns | Select-Object UserDisplayName, AppDisplayName, `
    @{N='Error';E={$_.Status.FailureReason}}, `
    CreatedDateTime, IPAddress | Format-Table

# Неактивные пользователи (не входили более 90 дней)
$Threshold = (Get-Date).AddDays(-90).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Inactive = Get-MgUser -All -Property DisplayName, UserPrincipalName, SignInActivity | 
    Where-Object {
        $_.SignInActivity.LastSignInDateTime -lt $Threshold -or 
        $null -eq $_.SignInActivity.LastSignInDateTime
    }

$Inactive | Select-Object DisplayName, UserPrincipalName, `
    @{N='LastSignIn';E={$_.SignInActivity.LastSignInDateTime}} | 
    Export-Csv "C:\inactive-users.csv" -NoTypeInformation -Encoding UTF8

Используйте эти отчёты для оптимизации лицензий: отзывайте лицензии у неактивных пользователей, экономя до 20–30% бюджета M365.

Часто задаваемые вопросы

Модуль AzureAD (и MSOnline) использует устаревший Azure AD Graph API, который Microsoft прекратит поддерживать. Microsoft Graph PowerShell SDK — официальная замена, покрывающая не только Azure AD, но и Exchange, Teams, SharePoint, Intune. Рекомендуется мигрировать все скрипты на Microsoft.Graph.

Для делегированного доступа (от имени пользователя): Mail.Send. Для серверного доступа (приложение): Mail.Send Application permission + Admin consent. Серверное разрешение позволяет отправлять от имени любого пользователя в тенанте — ограничьте его через Application Access Policy, если нужна отправка только от конкретных ящиков.

Microsoft Graph применяет throttling — ограничение запросов. При получении HTTP 429 (Too Many Requests) скрипт должен подождать время из заголовка Retry-After. В PowerShell SDK это обрабатывается автоматически. Для массовых операций используйте batch-запросы (Invoke-MgGraphRequest с JSON batch) — до 20 запросов в одном вызове.

Да, Graph API — это REST API, и его можно вызывать через Invoke-RestMethod. Получите токен через MSAL или клиентские учётные данные и отправляйте HTTP-запросы: Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/users' -Headers @{Authorization = "Bearer $token"}. Это полезно для простых сценариев без установки тяжёлого SDK.

Нужна помощь с настройкой?

Специалисты АйТи Фреш помогут с внедрением и настройкой — 15+ лет опыта, обслуживание от 15 000 ₽/мес

📞 Связаться с нами
#PowerShell Graph API#Microsoft Graph#автоматизация Microsoft 365#Microsoft Graph PowerShell#управление Azure AD#PowerShell Teams#автоматизация Exchange Online#Graph API примеры
Комментарии 0

Оставить комментарий

загрузка...