该脚本应该从多个 OU 中抓取用户并将用户分配给一个变量,然后从该变量中获取用户并根据超过 30 天的上次登录日期筛选每个用户。然后它将导出到包含我想要的一些信息的 CSV。
问题是,当我到达foreach部分,它搜索整个目录并且不使用我提供的变量中的用户。
任何批评意见也将不胜感激。
$30days = (get-date).adddays(-30)
$Users1 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users2 = Get-ADUser -SearchBase 'OU=Users-Remote,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users3 = Get-ADUser -SearchBase 'OU=Contractors,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users4 = Get-ADUser -SearchBase 'OU=Temps,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users5 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users6 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users = $Users1,$Users2,$Users3,$Users4,$Users5,$Users6
$useraccountsover30days = foreach ($user in $($Users)){Get-ADUser -filter {lastlogondate -le $30days} -Properties lastlogondate}
$lastlogonreadable = $useraccountsover30days | Select-Object SamAccountName,lastlogondate
$lastlogonreadable | Export-Csv C:/Users/myname/Desktop/Usersover30days.csv
答案1
我对您当前的脚本提出一些建议。
首先,单个大型查询几乎总是比多个小型查询表现更好。因此,get-aduser
我不会针对每个目标 OU 单独运行,而是将它们合并为一个调用,使用更高级别的通用 OU 作为搜索基础。显然,这最终可能会返回您不想包含的 OU 的结果。但稍后过滤掉这些结果会快得多。
您还会get-aduser
再次调用第一组查询中的每个结果,以过滤 lastLogonDate。但您可以将该过滤器与原始查询中的过滤器结合起来。这只是将版本转换为等效版本-ldapfilter
的问题。这样做的秘诀是知道 lastLogonDate 只是 lastLogonTimestamp 属性的 Powershell 转换版本。您可以将普通的 Powershell DateTime 值转换为 lastLogonTimestamp 使用的格式-filter
-ldapfilter
ToFileTime()
方法。
最后让我感到困惑的是(UserPrincipalName=*)
ldapfilter 的部分。在我接触过的每个域中,此属性始终会有一个值(就像 SamAccountName 或 DistinguishedName 一样)。它可能与默认值不同<SamAccoutnName>@<DomainFQDN>
,但永远不会为空。过滤器不一定会造成任何损害。AD 在不需要时花费 CPU 周期进行评估只是一件额外的事情。但如果您有理由相信它在您的环境中可能是空的,请务必保留它。
如果我正确理解了您的意图,那么我会这样修改您的脚本。
# make the comparison value using ToFileTime()
$30daysago = (Get-Date).AddDays(-30).ToFileTime()
# make the combined ldapfilter value
$LdapFilter = "(&(lastLogonTimestamp<=$30daysago)(extensionAttribute9=*)"
# make an array of the OU DNs you care about
$TargetOUs = @(
"OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com"
"OU=Users-Remote,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com"
"OU=Contractors,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com"
"OU=Temps,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com"
)
# define your common search base
$base = "OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com"
# get your combined results and the additional attributes you care about
$OldUsers = get-aduser -ldapfilter $LdapFilter -searchbase $base -pr lastLogonDate
# convert the target OU list into a regular expression we can compare each DN against in a single comparison call
$regex = ""
$TargetOUs | %{ $regex += ".*," + [Regex]::Escape($_) + "$|" }
$regex = $regex.Substring(0,$regex.Length-1)
# filter the results that aren't in your target OUs
# (depending on your OU layout, it might be more efficient to flip this
# and define the OUs you explicitly want to leave out)
$FilteredUsers = $OldUsers | ?{ $_.DistinguishedName -match $regex }
# export your CSV (sorted for good measure)
$FilteredUsers | select SamAccountName,LastLogonDate | sort LastLogonDate | export-csv C:/Users/myname/Desktop/Usersover30days.csv
PS 小心不要将lastLogonTimestamp
(或lastLogonDate
)视为 100% 准确。它可能来自设计上会过期 9 到 14 天。
答案2
我解决了对多个 OU 的类似请求,并通过指定 OU 多次重复相同的集合(如下所示):
get-aduser -filter 'enabled -eq $true' -Properties Name, LastLogonDate, AccountExpirationDate, description, Department, title, UserPrincipalName -SearchBase "OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com" | Where-object {$_.lastlogondate -lt (get-date).AddDays(-30)} | Select-Object Name, LastLogonDate, AccountExpirationDate, description, Department, title, UserPrincipalName | Export-csv C:\temp\users-nologin-30.csv -Encoding UTF8 -Append -NoTypeInformation -Force -Delimiter ";"
它获取所有已启用的帐户,包括属性名称、上次登录日期、帐户到期日期、说明、部门、标题、用户主体名称,并将其附加到 csv 文件中。如其他答案所述,30 天可能不准确,因此最好调用 44 天以确保万无一失。
如果“LastLogonDate”为空,则表示用户从未登录过,也许是一个新帐户。
答案3
您从未在 Get-ADUser 调用中使用过 $user 值...尝试将 $UsersX 值更改为需要发送给 Get-ADUser 的参数并替换它们...而且由于您重复使用相同的 LdapFilter,不妨将其也设为变量。(此外,您重复使用“OU=Users,OU=US-Location”三次,我认为这只是为了举例?)
$30days = (get-date).adddays(-30)
$LdapFilter = '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users1 = 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users2 = 'OU=Users-Remote,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users3 = 'OU=Contractors,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users4 = 'OU=Temps,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users5 = 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users6 = 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com'
$Users = $Users1,$Users2,$Users3,$Users4,$Users5,$Users6
$useraccountsover30days = foreach ($user in $($Users)){Get-ADUser -SearchBase $user -LdapFilter $LdapFilter -filter {lastlogondate -le $30days} -Properties lastlogondate}
$lastlogonreadable = $useraccountsover30days | Select-Object SamAccountName,lastlogondate
$lastlogonreadable | Export-Csv C:/Users/myname/Desktop/Usersover30days.csv