0

我有一个 powershell 脚本来检索来宾用户的最新登录信息。它工作正常。(基于https://gallery.technet.microsoft.com/office/Get-Guest-User-Last-Login-39f8237e

$startDate = "{0:yyyy-MM-dd}" -f (get-date).AddDays(-365)   #look 1 year back (not sure what the maximum is, but 1 year seems to work)
$endDate = "{0:yyyy-MM-dd}" -f (get-date)   #current date.
$externalUserExtention = "*#EXT#*"
$filePath="c:\temp\guest_user_last_logins.txt"

function logtoText($filePath, $msg) {
    $msg >> $filepath;
}

function find_last_login_date($user) {
    $lastLoginDate = Search-UnifiedAuditLog -UserIds $user.UserPrincipalName -StartDate $startDate -EndDate $endDate| Foreach-Object {$_.CreationDate = [DateTime]$_.CreationDate; $_} | Group-Object UserIds | Foreach-Object {$_.Group | Sort-Object CreationDate | Select-Object -Last 1} | Select CreationDate
    Write-Host "User " $user.UserPrincipalName "| Last Login Date -" $lastLoginDate.CreationDate
    logtoText $filePath ($user.UserPrincipalName + "," + $lastLoginDate.CreationDate)
    Write-Output $user.UserPrincipalName
}

Clear-Content $filePath
logtoText $filePath ('Username', 'Last Login DateTime')

#Get All External Users
$allExternalUsers = Get-MsolUser -All | Where-Object -FilterScript { $_.UserPrincipalName -Like $externalUserExtention }
ForEach($externalUser in $allExternalUsers) {
    find_last_login_date($externalUser)
}

输出如预期:

User user1@external.com#EXT#@tenant.onmicrosoft.com  | Last Login Date - 
user1@external.com#EXT#@tenant.onmicrosoft.com
User user2@external.com#EXT#@tenant.onmicrosoft.com  | Last Login Date - 11/04/2020 12:02:12 
user2@external.com#EXT#@tenant.onmicrosoft.com
...
User userNNNN@external.com#EXT#@tenant.onmicrosoft.com  | Last Login Date - 12/04/2020 14:22:25
userNNNN@external.com#EXT#@tenant.onmicrosoft.com
...

find_last_login_date 中额外的 Write-Output 仅用于调试。

现在,当我将其更改为 ForEach-Object 时,它会做一些奇怪的事情。可能对专家来说是有意义的,但对我来说不是:-)

代替

ForEach($externalUser in $allExternalUsers) {
    find_last_login_date($externalUser)
}

ForEach-Object -InputObject $allExternalUsers {
    find_last_login_date($_)
}

输出变为

User userX@external.com#EXT#@tenant.onmicrosoft.com | Last Login Date - 10/01/2021 14:05:36 05/01/2021 20:48:45 05/01/2021 16:09:25 04/01/2021 07:36:26 22/12/2020 08:01:07 19/12/2020 10:24:08 18/12/2020 14:20:51 18/12/2020 08:05:55 16/12/2020 17:32:28 14/12/2
020 08:20:56 13/12/2020 07:58:13 11/12/2020 10:58:58 10/12/2020 08:08:28
user1@external.com#EXT#@tenant.onmicrosoft.com
user2@external.com#EXT#@tenant.onmicrosoft.com
...
userNNNN@external.com#EXT#@tenant.onmicrosoft.com
...

所以它似乎触发脚本只查找最后一次登录日期,并且选择前 1 失败,等等。

知道我做错了什么吗?起初我认为这是关于“嵌套”的 ForEach-Object 但即使使用代码在函数内部进行搜索,它也会继续这样做。默认情况下是否并行执行操作,我是否需要等待所有任务完成?有什么不一样的?

我正在查看 ForEach-Object 以并行化上述脚本,因为在大型租户上运行需要很长时间。

4

1 回答 1

2

文档

当您将 InputObject 参数与 ForEach-Object 一起使用时,而不是将命令结果通过管道传送到 ForEach-Object,InputObject 值被视为单个对象。即使该值是作为命令结果的集合(例如 -InputObject (Get-Process))也是如此。由于 InputObject 无法从对象数组或对象集合中返回单个属性,因此我们建议如果您使用 ForEach-Object 对对象集合执行操作,这些对象在已定义属性中具有特定值的对象,则在管道中使用 ForEach-Object .

改变

ForEach-Object -InputObject $allExternalUsers {
    find_last_login_date($_)
}

进入

$allExternalUsers | ForEach-Object {
    find_last_login_date($_)
}
于 2021-01-11T12:26:41.443 回答