[玩转系统] 来自 PowerShell 的 Active Directory 更改报告
作者:精品下载站 日期:2024-12-14 08:01:24 浏览:13 分类:玩电脑
来自 PowerShell 的 Active Directory 更改报告
几天前,我发布了一些 PowerShell 代码,您可以使用这些代码在 Active Directory 中发生变化时收到警报。该代码使用 PowerShell 和 CIM 事件来通知您,例如,当创建新用户帐户时。当您需要警报时,这会很有帮助。但也许您只需要报告。自给定日期和时间(例如过去 24 小时)以来,Active Directory 中发生了哪些变化?如果能有一份漂亮的报告不是很好吗?让我来帮忙。以下是我如何使用 PowerShell 和 ActiveDirectory 模块解决该问题。
何时改变
Active Directory 中的对象具有 WhenChanged 属性。许多 ActiveDirectory 命令都有过滤器参数。这个参数非常灵活,你一定要阅读它的命令帮助。使用过滤器的原因是对象是在源头过滤的,速度要快得多。这不是推荐的过滤方式:
$since = (Get-Date).AddMinutes(-90)
Get-ADuser -filter * -properties WhenChanged | Where { $_.WhenChanged -ge $since }
它会起作用,但请考虑一下。您告诉 PowerShell,“从域中获取所有用户对象,将它们发送到我的计算机,然后过滤 WhenChanged 属性大于过去 90 分钟的位置。”在小域中,您不会注意到。但如果你有很大的域,那就有明显的区别。
相反,创建一个像这样的过滤器:
Get-ADuser -filter {WhenChanged -ge $since} -Properties WhenChanged |
Select-Object DistinguishedName,Name,WhenChanged
棘手的部分是您需要将这个特定的过滤器创建为脚本块。我有一段时间没有编写任何 AD 脚本了,花了一些时间才解决这个问题。我重新阅读了 cmdlet 帮助,这让我朝着正确的方向前进。请务必阅读帮助。
这是我的结果。当然,我不知道发生了什么变化,但我并不担心。需要记住的一件事是,您可能已经更改了对象,其中唯一的更改是由于复制和 USN 更新造成的。我还没有找到过滤掉这些类型的更改的好方法。
获取 ADObject
对于我的报告,我只关心用户、组、计算机和 OU。虽然我可以使用特定的 Get-* cmdlet,但使用 Get-ADObject 并创建良好的过滤器可能同样容易。
$filter = {(objectclass -eq 'user' -or objectclass -eq 'group' -or objectclass -eq 'organizationalunit' ) -AND (WhenChanged -gt $since )}
这是我使用此过滤器的一种方法。
Get-ADObject -Filter $filter -Properties WhenCreated,WhenChanged |
Sort-Object -Property ObjectClass,WhenChanged |
Format-Table -GroupBy objectClass -Property DistinguishedName,WhenCreated,WhenChanged
需要指出的一件事是,如果 WhenCreated 大于或等于我的截止日期,则很可能是一个新对象。
使用 Get-ADObject 的另一个原因是它还会显示已删除的对象。但是,您需要启用 Active Directory 回收站。但如果你有的话,这里是修改后的代码:
Get-ADObject -Filter $filter -Properties WhenCreated,WhenChanged -IncludeDeletedObjects |
Select-Object *,@{Name="IsNew";Expression = { if ($_.WhenCreated -ge $since) { $True} else {$False}}},
@{Name="IsDeleted";Expression = {$_.distinguishedname -match "Deleted Objects" }} |
Sort-Object -Property ObjectClass,WhenChanged |
Format-List -GroupBy objectClass -Property DistinguishedName,WhenCreated,WhenChanged,IsNew,IsDeleted
我正在定义一些附加属性来指示新的或已删除的对象。
您也可以使用一个名为 IsDeleted 的属性,尽管它仅存在于已删除的对象上。我的代码为所有对象定义了它。
一旦获得了对象和属性,就可以无休止地格式化或使用结果。
创建 HTML 报告
我喜欢创建报告,我最喜欢的工具是 ConvertTo-Html。在我的报告脚本中,我倾向于创建具有嵌入式样式的独立文件。如果您计划通过电子邮件发送文件,这是一个好方法。我的脚本实际上是一个控制脚本,包含 AD、ConvertTo-HTML 和 Out-File cmdlet。我没有编写一个函数来将对象发送到管道。我正在运行一组精心设计的 PowerShell 命令来产生所需的结果。这是一个控制脚本。
这些类型的脚本也可以有参数。我经常将脚本参数传递给底层 cmdlet,通常使用 PSBoundParameters 和 splatting。尽管最近我一直在使用私有版本 $PSDefaultParameterValues,这正是我在此脚本中使用的版本。我现在不妨向您展示一下。
#requires -module ActiveDirectory
#Reporting on deleted items requires the Active Directory Recycle Bin feature
[cmdletbinding()]
Param(
[Parameter(Position = 0,HelpMessage = "Enter a last modified datetime for AD objects. The default is the last 8 hours.")]
[ValidateNotNullOrEmpty()]
[datetime]$Since = ((Get-Date).AddHours(-8)),
[Parameter(HelpMessage = "What is the report title?")]
[string]$ReportTitle = "Active Directory Change Report",
[Parameter(HelpMessage = "Add a second grouping based on the object's container or OU.")]
[switch]$ByContainer,
[Parameter(HelpMessage = "Specify the path for the output file.")]
[ValidateNotNullOrEmpty()]
[string]$Path = ".\ADChangeReport.html",
[Parameter(HelpMessage = "Specifies the Active Directory Domain Services domain controller to query. The default is your Logon server.")]
[string]$Server = $env:LOGONSERVER.SubString(2),
[Parameter(HelpMessage = "Specify an alternate credential for authentication.")]
[pscredential]$Credential,
[ValidateSet("Negotiate","Basic")]
[string]$AuthType
)
#region helper functions
#a private helper function to convert the objects to html fragments
Function _convertObjects {
Param([object[]]$Objects)
#convert each table to an XML fragment so I can insert a class attribute
[xml]$frag = $objects | Sort-Object -property WhenChanged |
Select-Object -Property DistinguishedName,Name,WhenCreated,WhenChanged,IsDeleted |
ConvertTo-Html -Fragment
for ($i = 1; $i -lt $frag.table.tr.count;$i++) {
if (($frag.table.tr[$i].td[2] -as [datetime]) -ge $since) {
#highlight new objects in green
$class = $frag.CreateAttribute("class")
$class.value="new"
[void]$frag.table.tr[$i].Attributes.append($class)
} #if new
#insert the alert attribute if the object has been deleted.
if ($frag.table.tr[$i].td[-1] -eq 'True') {
#highlight deleted objects in red
$class = $frag.CreateAttribute("class")
$class.value="alert"
[void]$frag.table.tr[$i].Attributes.append($class)
} #if deleted
} #for
#write the innerXML (ie HTML code) as the function output
$frag.InnerXml
}
# private helper function to insert javascript code into my html
function _insertToggle {
[cmdletbinding()]
#The text to display, the name of the div, the data to collapse, and the heading style
#the div Id needs to be simple text
Param([string]$Text, [string]$div, [object[]]$Data, [string]$Heading = "H2", [switch]$NoConvert)
$out = [System.Collections.Generic.list[string]]::New()
if (-Not $div) {
$div = $Text.Replace(" ", "_")
}
$out.add("<a href='javascript:toggleDiv(""$div"");' title='click to collapse or expand this section'><$Heading>$Text</$Heading></a><div id=""$div"">")
if ($NoConvert) {
$out.Add($Data)
}
else {
$out.Add($($Data | ConvertTo-Html -Fragment))
}
$out.Add("</div>")
$out
}
#endregion
#some report metadata
$reportVersion = "2.1.1"
$thisScript = Convert-Path $myinvocation.InvocationName
Write-Verbose "[$(Get-Date)] Starting $($myinvocation.MyCommand)"
Write-Verbose "[$(Get-Date)] Detected these bound parameters"
$PSBoundParameters | Out-String | Write-Verbose
#set some default parameter values
$params = "Credential","AuthType"
$script:PSDefaultParameterValues = @{"Get-AD*:Server" = $Server}
ForEach ($param in $params) {
if ($PSBoundParameters.ContainsKey($param)) {
Write-Verbose "[$(Get-Date)] Adding 'Get-AD*:$param' to script PSDefaultParameterValues"
$script:PSDefaultParameterValues["Get-AD*:$param"] = $PSBoundParameters.Item($param)
}
}
Write-Verbose "[$(Get-Date)] Getting current Active Directory domain"
$domain = Get-ADDomain
#create a list object to hold all of the HTML fragments
Write-Verbose "[$(Get-Date)] Initializing fragment list"
$fragments = [System.Collections.Generic.list[string]]::New()
$fragments.Add("<H2>$($domain.dnsroot)</H2>")
$fragments.Add("<a href='javascript:toggleAll();' title='Click to toggle all sections'>+/-</a>")
Write-Verbose "[$(Get-Date)] Querying $($domain.dnsroot)"
$filter = {(objectclass -eq 'user' -or objectclass -eq 'group' -or objectclass -eq 'organizationalunit' ) -AND (WhenChanged -gt $since )}
Write-Verbose "[$(Get-Date)] Filtering for changed objects since $since"
$items = Get-ADObject -filter $filter -IncludeDeletedObjects -Properties WhenCreated,WhenChanged,IsDeleted -OutVariable all | Group-Object -property objectclass
Write-Verbose "[$(Get-Date)] Found $($all.count) total items"
if ($items.count -gt 0) {
foreach ($item in $items) {
$category = "{0}{1}" -f $item.name[0].ToString().toUpper(),$item.name.Substring(1)
Write-Verbose "[$(Get-Date)] Processing $category [$($item.count)]"
if ($ByContainer) {
Write-Verbose "[$(Get-Date)] Organizing by container"
$subgroup = $item.group | Group-Object -Property { $_.distinguishedname.split(',', 2)[1] } | Sort-Object -Property Name
$fraghtml = [System.Collections.Generic.list[string]]::new()
foreach ($subitem in $subgroup) {
Write-Verbose "[$(Get-Date)] $($subItem.name)"
$fragGroup = _convertObjects $subitem.group
$divid = $subitem.name -replace "=|,",""
$fraghtml.Add($(_inserttoggle -Text "$($subItem.name) [$($subitem.count)]" -div $divid -Heading "H4" -Data $fragGroup -NoConvert))
} #foreach subitem
} #if by container
else {
$fragHtml = _convertObjects $item.group
}
$code = _insertToggle -Text "$category [$($item.count)]" -div $category -Heading "H3" -Data $fragHtml -NoConvert
$fragments.Add($code)
} #foreach item
#my embedded CSS
$head = @"
<Title>$ReportTitle</Title>
<style>
h2 {
width:95%;
background-color:#7BA7C7;
font-family:Tahoma;
font-size:12pt;
}
h4 {
width:95%;
background-color:#b5f144;
}
body {
background-color:#FFFFFF;
font-family:Tahoma;
font-size:12pt;
}
td, th {
border:1px solid black;
border-collapse:collapse;
}
th {
color:white;
background-color:black;
}
table, tr, td, th {
padding-left: 10px;
margin: 0px
}
tr:nth-child(odd) {background-color: lightgray}
table {
width:95%;
margin-left:5px;
margin-bottom:20px;
}
.alert { color:red; }
.new { color:green; }
.footer { font-size:10pt; }
.footer tr:nth-child(odd) {background-color: white}
.footer td,tr {
border-collapse:collapse;
border:none;
}
.footer table {width:15%;}
td.size {
text-align: right;
padding-right: 25px;
}
</style>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'>
</script>
<script type='text/javascript'>
function toggleDiv(divId) {
`$("#"+divId).toggle();
}
function toggleAll() {
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
`$("#"+div.id).toggle();
}
}
</script>
<H1>$ReportTitle</H1>
"@
#a footer for the report. This could be styled with CSS
$post = @"
<table class='footer'>
<tr align = "right"><td>Report run: <i>$(Get-Date)</i></td></tr>
<tr align = "right"><td>Report version: <i>$ReportVersion</i></td></tr>
<tr align = "right"><td>Source: <i>$thisScript</i></td></tr>
</table>
"@
$htmlParams = @{
Head = $head
precontent = "Active Directory changes since $since. Reported from $($Server.toUpper()). Replication only changes may be included."
Body =($fragments | Out-String)
PostContent = $post
}
Write-Verbose "[$(Get-Date)] Creating report $ReportTitle version $reportversion saved to $path"
ConvertTo-HTML @htmlParams | Out-File -FilePath $Path
Get-Item -Path $Path
}
else {
Write-Warning "No modified objects found in the $($domain.dnsroot) domain since $since."
}
Write-Verbose "[$(Get-Date)] Ending $($myinvocation.MyCommand)"
该脚本创建一系列 HTML 片段,最终将它们组合在一起创建最终文件。我的脚本包含一些辅助函数。其中之一将 HTML 解析为 XML,以便我可以插入一个类属性来指示该对象是新的还是已删除。我有一个定义的样式,以红色显示已删除的对象,以绿色显示新对象。另一个函数帮助我插入 JavaScript,让我可以折叠文件的各个部分。
c:\scripts\ADChangeReport.ps1 -Since (Get-Date).Addhours(-1) -Path c:\scripts\ad6.html
尽管您可以指定不同的域控制器,但该脚本将默认使用当前用户的登录服务器。您还可以指定备用凭据。您可以而且应该从域成员桌面运行该脚本。
我可以单击 +/- 来切换折叠所有区域,或单击不同的类别。您可以看到绿色文本的新组。
在报告的底部,您可以看到红色的已删除用户。我还喜欢在报告的页脚中包含元数据信息。此信息帮助我了解该报告的来源。如果您设置了计划报告系统但忘记记录它,这会很有帮助。此报告中缺少的一项信息是计算机名称。我可以看到脚本文件的路径,但不知道是哪台计算机。我会把调整留给你。
报告脚本还支持按容器组织结果。我的代码将在通过分割专有名称获得的对象容器上进行分组。
if ($ByContainer) {
Write-Verbose "[$(Get-Date)] Organizing by container"
$subgroup = $item.group | Group-Object -Property { $_.distinguishedname.split(',', 2)[1] } | Sort-Object -Property Name
...
概括
这是一个公认的复杂的 PowerShell 脚本,因此如果您有任何不理解或有疑问,请随时在评论中提问。我还要指出,就像 AD 事件监视器一样,仅仅因为您可以使用这样的东西并不意味着您应该使用。只需进行最少更改的小型域就可以使用此脚本或类似的脚本。
不过,我对在具有高度动态的 Active Directory 基础设施的大型企业中使用它持怀疑态度。尽管如果你的改变窗口很小,它可能会有效。我假设,如果您正在运行大型 AD 环境,那么您的公司已投资于高质量且适当的管理和报告工具。您可以利用 PowerShell 来处理这些利基或特殊情况。
如果您可以尝试一下报告脚本,我很想听听您的经验。享受!
猜你还喜欢
- 03-30 [玩转系统] 如何用批处理实现关机,注销,重启和锁定计算机
- 02-14 [系统故障] Win10下报错:该文件没有与之关联的应用来执行该操作
- 01-07 [系统问题] Win10--解决锁屏后会断网的问题
- 01-02 [系统技巧] Windows系统如何关闭防火墙保姆式教程,超详细
- 12-15 [玩转系统] 如何在 Windows 10 和 11 上允许多个 RDP 会话
- 12-15 [玩转系统] 查找 Exchange/Microsoft 365 中不活动(未使用)的通讯组列表
- 12-15 [玩转系统] 如何在 Windows 上安装远程服务器管理工具 (RSAT)
- 12-15 [玩转系统] 如何在 Windows 上重置组策略设置
- 12-15 [玩转系统] 如何获取计算机上的本地管理员列表?
- 12-15 [玩转系统] 在 Visual Studio Code 中连接到 MS SQL Server 数据库
- 12-15 [玩转系统] 如何降级 Windows Server 版本或许可证
- 12-15 [玩转系统] 如何允许非管理员用户在 Windows 中启动/停止服务
取消回复欢迎 你 发表评论:
- 精品推荐!
-
- 最新文章
- 热门文章
- 热评文章
[影视] 黑道中人 Alto Knights(2025)剧情 犯罪 历史 电影
[古装剧] [七侠五义][全75集][WEB-MP4/76G][国语无字][1080P][焦恩俊经典]
[实用软件] 虚拟手机号 电话 验证码 注册
[电视剧] 安眠书店/你 第五季 You Season 5 (2025) 【全10集】
[电视剧] 棋士(2025) 4K 1080P【全22集】悬疑 犯罪 王宝强 陈明昊
[软件合集] 25年6月5日 精选软件22个
[软件合集] 25年6月4日 精选软件36个
[短剧] 2025年06月04日 精选+付费短剧推荐33部
[短剧] 2025年06月03日 精选+付费短剧推荐25部
[软件合集] 25年6月3日 精选软件44个
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电视剧] 欢乐颂.5部全 (2016-2024)
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[影视] 【稀有资源】香港老片 艺坛照妖镜之96应召名册 (1996)
[剧集] 神经风云(2023)(完结).4K
[剧集] [BT] [TVB] [黑夜彩虹(2003)] [全21集] [粤语中字] [TV-RMVB]
[实用软件] 虚拟手机号 电话 验证码 注册
[资源] B站充电视频合集,包含多位重量级up主,全是大佬真金白银买来的~【99GB】
[影视] 内地绝版高清录像带 [mpg]
[书籍] 古今奇书禁书三教九流资料大合集 猎奇必备珍藏资源PDF版 1.14G
[电视剧] [突围] [45集全] [WEB-MP4/每集1.5GB] [国语/内嵌中文字幕] [4K-2160P] [无水印]
[剧集] [央视][笑傲江湖][2001][DVD-RMVB][高清][40集全]李亚鹏、许晴、苗乙乙
[电影] 美国队长4 4K原盘REMUX 杜比视界 内封简繁英双语字幕 49G
[电影] 死神来了(1-6)大合集!
[软件合集] 25年05月13日 精选软件16个
[精品软件] 25年05月15日 精选软件18个
[绝版资源] 南与北 第1-2季 合集 North and South (1985) /美国/豆瓣: 8.8[1080P][中文字幕]
[软件] 25年05月14日 精选软件57个
[短剧] 2025年05月14日 精选+付费短剧推荐39部
[短剧] 2025年05月15日 精选+付费短剧推荐36部
- 最新评论
-
- 热门tag