SearchUnifiedAuditLog 的 ForEach-Object 更改结果

问题描述

我有一个 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 来并行化上述脚本,因为在大型租户上运行需要很长时间。

解决方法

来自the docs

当您将 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($_)
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...