最近因为疫情嘛,大家伙都在家里工作。老板隔三差五的让我给他一些报告,比如最近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来进行访问的。
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
注册一个新的 application, redirect url 可以随便写一个,这个主要是取决于验证方式,如果不用这种验证方式,可以不写
注册之后,记录一下 Application(Client) ID,这个相当于application的用户名
我们再给这个application 创建一个 secrets,这个相当于这个application的密码
接下来,在API permissions里面给这个application授权。他默认只有 Graph的 delegated的User.Read 权限
我们可以添加新的权限,选择 Microsoft Graph
这里我们选择 Delegation ,这样授权生成Token的时候,他会通过我的用户的权限进行授权
接下来是重点,到底需要什么权限呢?这个权限我们需要查看Graph的API 手册,他会告诉每一个操作对应的权限。比如我想查看安全警告,那么我搜索 Security的Alert的操作, 原来我需要添加下面的权限
https://docs.microsoft.com/en-us/graph/api/alert-get?view=graph-rest-1.0&tabs=http
添加之后,点击 Grant admin consent
准备工作就做好了,接下来看看我们的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='admin@test.com'
$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
接下来的操作就很简单了
我想获取最新的安全警告,对应的API文档如下
https://docs.microsoft.com/en-us/graph/api/alert-list?view=graph-rest-1.0&tabs=http
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
再看几个例子
类似的操作,我们可以查看API的手册,添加对应的application permission,然后执行不同请求。
比如 我想查看90天内所有用户对SharePoint的访问情况,先添加Reports.Read.All的权限
然后执行
$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
再比如,我想查看 所有人的邮箱使用情况,发送了多少邮件,接受了多少邮件,同样的先添加权限
然后执行代码,查看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
有的时候,可能觉得查看API手册不是太方便,微软提供了一个更便捷的方式,用户可以直接访问 Graph Explorer。
https://developer.microsoft.com/en-us/graph/graph-explorer
这个界面可以直接执行对应的API操作,返回结果,还提供了大量的常用查询和需要的权限。这样子我的操作就更简单了,可以在这个网页进行测试,成功之后,再修改自己的脚本。
最后,附上一个完整的脚本
#获取Token
$clientId = "8d4538e6-b1a5-4c05-b449-54d62ss18413"
$tenantName = "test.com"
$clientSecret = ".2S_zsp.dVff~~5J_9_cxM1e1TRXrJ94"
$resource = "https://graph.microsoft.com/"
$username='test@abc.com'
$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=@"
<style>
body {
color:#333333;
font-family:Calibri,Tahoma;
font-size: 10pt;
}
h1 {
text-align:center;
}
h2 {
border-top:1px solid #666666;
}
th {
font-weight:bold;
color:#eeeeee;
background-color:#333333;
cursor:pointer;
}
.odd { background-color:#ffffff; }
.even { background-color:#dddddd; }
.paginate_enabled_next, .paginate_enabled_previous {
cursor:pointer;
border:1px solid #222222;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.paginate_disabled_previous, .paginate_disabled_next {
color:#666666;
cursor:pointer;
background-color:#dddddd;
padding:2px;
margin:4px;
border-radius:2px;
}
.dataTables_info { margin-bottom:4px; }
.sectionheader { cursor:pointer; }
.sectionheader:hover { color:red; }
.grid { width:100% }
.red {
color:red;
font-weight:bold;
}
.green{
color:green;
font-weight:bold;
}
</style>
"@
#发送邮件
$from = "test@abc.com"
$to = "aaa@abc.com"
$smtp = "smtp.office365.com"
$sub = "Security Alerts Lists"
$password = Get-Content "C:\temp\password.txt" | ConvertTo-SecureString
$mycreds = New-Object System.Management.Automation.PsCredential("xyli@vet.partners",$password)
$htmlbody=$ret| select AccountName, DomainName,LogonDateTime, LogonIP, UserPrincipalName, Category, Severity, Title | sort Severity| ConvertTo-Html -Body "<H1> Secuirty Alerts </H1>" -Head $style
Send-MailMessage -To $to -From $from -Subject $sub -Body ($htmlbody|Out-String) -Credential $mycreds -SmtpServer $smtp -DeliveryNotificationOption Never -BodyAsHtml -UseSsl -port 587
收到的邮件通知
参考资料:
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
来源:oschina
链接:https://my.oschina.net/u/4404102/blog/4496988