最近因为疫情嘛,大家伙都在家里工作。老板隔三差五的让我给他一些报告,比如最近SharePoint的用户使用情况啦,比如Office365 邮箱的收发频率啦,还有Azure账号的risky signin等等,这样子可以让他更好地了解大家的工作强度(有没有偷懒!)和系统安全性等等。 Azure和Office365都有现成的报表和图像界面可以搜索和下载这些资料,但是比较繁琐,需要拿鼠标点半天,那么有没有自动化的可能呢?

在网上搜了搜,没有找到现成的PowerShell模块和函数可以用的,不过呢,豆子发现我们可以直接对Azure Graph 进行查询获取结果。 Azure Graph 是一个Azure 的 Rest API 接口,这个接口允许用户通过http/https 的 get或者post请求可以对O365,Azure AD,SharePoints,teams,Exchange等等服务直接进行读写操作。事实上,很多第三方的软件,比如Veeam 365的备份功能,比如一些Azure App的 SSO的功能,都是就是通过这个API来和Azure进行互动的。豆子自然也是可以用PowerShell来进行访问的。

PowerShell 访问 Azure Graph API 生成报表_第1张图片

Graph提供了一个接口 https://graph.microsoft.com 来接受 http/https 的get/post 的请求。首先,用户需要获取一个有效的授权token来执行相关的操作的权限。简单的说,为了获取这个Token,用户需要在Azure Portal里面创建一个application,然后授权相关的api 权限,然后用户发送一个post请求给微软的oauth服务,从而获得一个临时的Token。
api的权限分为application和 delegation的权限,前者表示我注册的applciation本身具有的权限,后者表示我在这个application上登陆的用户的权限,最终的有效权限则是两者的交集。很多常见服务的操作,既可以通过application进行权限,也可以通过delegation来授权,但是有些特殊的服务,比如安全方面的报告,Azure明确要求用户具有P2以上的license才可以操作,那么就只能通过delegation来授权。

关于具体的授权和验证, Azure提供了多种方式,每种方式都有自己的应用场景,这里豆子演示一个最常用的方式(也是我上面提到的通过delegation给指定用户来授权)。

首先 登陆 Azure Portal,新建一个application

PowerShell 访问 Azure Graph API 生成报表_第2张图片

注册一个新的 application, redirect url 可以随便写一个,这个主要是取决于验证方式,如果不用这种验证方式,可以不写

PowerShell 访问 Azure Graph API 生成报表_第3张图片

注册之后,记录一下 Application(Client) ID,这个相当于application的用户名
PowerShell 访问 Azure Graph API 生成报表_第4张图片

我们再给这个application 创建一个 secrets,这个相当于这个application的密码

PowerShell 访问 Azure Graph API 生成报表_第5张图片

接下来,在API permissions里面给这个application授权。他默认只有 Graph的 delegated的User.Read 权限

PowerShell 访问 Azure Graph API 生成报表_第6张图片

我们可以添加新的权限,选择 Microsoft Graph

PowerShell 访问 Azure Graph API 生成报表_第7张图片

这里我们选择 Delegation ,这样授权生成Token的时候,他会通过我的用户的权限进行授权

PowerShell 访问 Azure Graph API 生成报表_第8张图片

接下来是重点,到底需要什么权限呢?这个权限我们需要查看Graph的API 手册,他会告诉每一个操作对应的权限。比如我想查看安全警告,那么我搜索 Security的Alert的操作, 原来我需要添加下面的权限

https://docs.microsoft.com/en-us/graph/api/alert-get?view=graph-rest-1.0&tabs=http

PowerShell 访问 Azure Graph API 生成报表_第9张图片

添加之后,点击 Grant admin consent

PowerShell 访问 Azure Graph API 生成报表_第10张图片

准备工作就做好了,接下来看看我们的PowerShell 代码。

下面代码会生成对应的Token,替换掉对应的参数即可。这段代码其实就是把application的用户名和密码,我的用户的用户名和密码一起发送出去,获取到一个临时权限的Token。

$clientId = "f4b6b7ec-68f3-420a-bd7e-bc6fe5a918d1"
$tenantName = "abc.com.au"
$clientSecret = "~mFs5EX4Fv9-82OsseQxhH.n0Su8L_Ei-7"
$resource = "https://graph.microsoft.com/"
$username='[email protected]'
$password='SafeappPassword@'

$ReqTokenBody = @{
    Grant_Type    = "Password"
    client_Id     = $clientID
    Client_Secret = $clientSecret
    Username      = $Username
    Password      = $Password
    Scope         = "https://graph.microsoft.com/.default"
} 

$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody

PowerShell 访问 Azure Graph API 生成报表_第11张图片

接下来的操作就很简单了

我想获取最新的安全警告,对应的API文档如下

https://docs.microsoft.com/en-us/graph/api/alert-list?view=graph-rest-1.0&tabs=http

PowerShell 访问 Azure Graph API 生成报表_第12张图片

PowerShell 发送请求,获得结果,我过滤一下,输出结果


$data=(Invoke-RestMethod -uri "https://graph.microsoft.com/v1.0/security/alerts" -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Method Get) 
$data.value | Where-Object {$_.severity -notlike '*low*'} | select eventDateTime,Category, severity, title, userStates | ft

PowerShell 访问 Azure Graph API 生成报表_第13张图片

再看几个例子

类似的操作,我们可以查看API的手册,添加对应的application permission,然后执行不同请求。

比如 我想查看90天内所有用户对SharePoint的访问情况,先添加Reports.Read.All的权限

PowerShell 访问 Azure Graph API 生成报表_第14张图片

然后执行

$data=(Invoke-RestMethod -uri "https://graph.microsoft.com/v1.0/reports/getSharePointActivityUserDetail(period='D90')" -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Method Get) -replace "", "" 
$data | ConvertFrom-Csv | ft

PowerShell 访问 Azure Graph API 生成报表

再比如,我想查看 所有人的邮箱使用情况,发送了多少邮件,接受了多少邮件,同样的先添加权限

PowerShell 访问 Azure Graph API 生成报表_第15张图片

然后执行代码,查看7天内的情况


$data=(Invoke-RestMethod -uri "https://graph.microsoft.com/v1.0/reports/getEmailActivityUserDetail(period='D7')" -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Method Get) -replace "", "" 
$data | ConvertFrom-Csv | out-gridview

PowerShell 访问 Azure Graph API 生成报表_第16张图片

有的时候,可能觉得查看API手册不是太方便,微软提供了一个更便捷的方式,用户可以直接访问 Graph Explorer。
https://developer.microsoft.com/en-us/graph/graph-explorer

这个界面可以直接执行对应的API操作,返回结果,还提供了大量的常用查询和需要的权限。这样子我的操作就更简单了,可以在这个网页进行测试,成功之后,再修改自己的脚本。
PowerShell 访问 Azure Graph API 生成报表_第17张图片

最后,附上一个完整的脚本

#获取Token

$clientId = "8d4538e6-b1a5-4c05-b449-54d62ss18413"
$tenantName = "test.com"
$clientSecret = ".2S_zsp.dVff~~5J_9_cxM1e1TRXrJ94"
$resource = "https://graph.microsoft.com/"
$username='[email protected]'
$password = '@@222333' 

$ReqTokenBody = @{
    Grant_Type    = "Password"
    client_Id     = $clientID
    Client_Secret = $clientSecret
    Username      = $Username
    Password      = $Password
    Scope         = "https://graph.microsoft.com/.default"
} 

$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody

# 通过API获取安全警告

$data=(Invoke-RestMethod -uri "https://graph.microsoft.com/v1.0/security/alerts" -Headers @{Authorization = "Bearer $($Tokenresponse.access_token)"} -Method Get) 
$all=$data.value | Where-Object {$_.severity -like '*medium*' -or $_.severity -like "*high"} 

$ret=@()

foreach($one in $all){

$obj=$one.userStates 
$category=$one.category
$Severity=$one.severity
$title=$one.title

$obj | Add-Member -NotePropertyName Category -NotePropertyValue $category
$obj | Add-Member -NotePropertyName Severity -NotePropertyValue $Severity
$obj | Add-Member -NotePropertyName Title -NotePropertyValue $title

$ret+=$obj
}

$ret

#自定义一个CSS界面,用于发送对应的邮件,显示一个比较好看些的table界面
$style=@"


"@

#发送邮件

$from = "[email protected]"
$to = "[email protected]"
$smtp = "smtp.office365.com" 
$sub = "Security Alerts Lists" 
$password = Get-Content "C:\temp\password.txt" | ConvertTo-SecureString 
$mycreds = New-Object System.Management.Automation.PsCredential("[email protected]",$password)

$htmlbody=$ret| select AccountName, DomainName,LogonDateTime, LogonIP, UserPrincipalName, Category, Severity, Title | sort Severity| ConvertTo-Html -Body "

Secuirty Alerts

" -Head $style Send-MailMessage -To $to -From $from -Subject $sub -Body ($htmlbody|Out-String) -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAsHtml -UseSsl -port 587

收到的邮件通知

PowerShell 访问 Azure Graph API 生成报表_第18张图片

参考资料:

https://developer.microsoft.com/en-us/graph/graph-explorer
https://adamtheautomator.com/microsoft-graph-api-powershell/
https://docs.microsoft.com/en-us/graph/overview?view=graph-rest-1.0