0

我正在编写一个 Powershell 脚本来获取过去 7 天内登录/退出服务器的所有用户,他们的名字不像“*-organization”。以下有效,但无论我尝试什么,我都无法过滤名称

$logs = get-eventlog system -ComputerName $env:computername -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7)
$res = @()
ForEach ($log in $logs)
{
    if($log.instanceid -eq 7001){
        $type = "Logon"
    }
    Elseif ($log.instanceid -eq 7002){
        $type = "Logoff"
    }
    Else { Continue } 
    
    $res += New-Object PSObject -Property @{Time = $log.TimeWritten; "Event" = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
$res

我试过在不同的地方和方式添加这条线,但无论如何我都无法过滤它。它要么失败并告诉我我的操作员必须有一个属性和值,要么它运行良好并忽略任何用户名过滤。

| Where-Object $_.User -notlike "*-organization"

甚至可以用这种方法过滤登录用户名吗?如果是这样,我做错了什么?如果不可能,有没有其他方法可以得到我需要的东西?

4

3 回答 3

1

必须有一个名为“用户”的属性才能工作。get-eventlog 现在实际上已经过时了,取而代之的是 get-winevent。不幸的是,您必须进入 xml 才能按用户 ID 进行过滤。我已经包含了一个时间过滤器。

$a = get-winevent @{logname='system';
  providername='Microsoft-Windows-Winlogon'} -MaxEvents 1
$e = $a.ToXml() -as 'xml'
$e.event.EventData

Data
----
{TSId, UserSid}

get-winevent @{logname='system';providername='Microsoft-Windows-Winlogon';
  data='S-2-6-31-1528843147-473324174-2919417754-2001';starttime=(Get-Date).AddDays(-7);
  id=7001,7002}

在 powershell 7 中,您可以直接引用名为 data 字段的 eventdata:

get-winevent @{logname='system';providername='Microsoft-Windows-Winlogon';
  usersid='S-2-6-31-1528843147-473324174-2919417754-2001'}

get-winevent 文档说您可以在 filterhashtable 中使用“userid”,但我无法让它工作。

编辑:实际上这有效。但是不要限制太多,至少对我来说是这样。

get-winevent @{logname='system';userid='js2010'}
get-winevent @{providername='Microsoft-Windows-Winlogon';userid='js2010'}
于 2020-07-24T18:43:01.930 回答
0

您可以使用如下-FilterXPath参数执行此操作:

$filter = "(*[System/EventID=7001] or *[System/EventID=7002]) and *[System/Provider[@Name='Microsoft-Windows-Winlogon']]"
$result = Get-WinEvent -LogName System -FilterXPath $filter | ForEach-Object {
    # convert the event to XML and grab the Event node
    $eventXml = ([xml]$_.ToXml()).Event
    $eventData = $eventXml.EventData.Data

    $userSID = ($eventData | Where-Object { $_.Name -eq 'UserSid' }).'#text'
    $userName = [System.Security.Principal.SecurityIdentifier]::new($userSID).Translate([System.Security.Principal.NTAccount])

    # you can add username filtering here if you like.
    # remember the $userName is in formal DOMAIN\LOGONNAME
    # if ($username -notlike "*-organization") {
        # output the properties you need
        [PSCustomObject]@{
            Time     = [DateTime]$eventXml.System.TimeCreated.SystemTime
            Event    = if ($eventXml.System.EventID -eq 7001) { 'LogOn' } else { 'LogOff' }
            UserName = $userName
            UserSID  = $userSID
            Computer = $eventXml.System.Computer

        }
    # }
}

# output on screen
$result

# output to CSV file
$result | Export-Csv -Path 'X:\TheOutputFile.csv' -NoTypeInformation

注意,我已经注释掉了代码中的用户名过滤。它只是为了让您了解放置它的位置。当然,你也可以在$result之后过滤:

$result | Where-Object { $_.UserName -notlike "*-organization" }
于 2020-07-25T11:55:49.017 回答
0

添加到@js2010 的有用答案,并假设您使用的是 PowerShell 5.1。我通常标识属性数组索引并Select-Object根据需要使用来创建自定义属性。

$WinEvents = 
get-winevent @{logname='system'; providername='Microsoft-Windows-Winlogon'} | 
Select-Object @{Name = 'Time'; Expression = {$_.TimeCreated}},
    @{Name = 'Event'; Expression = { If($_.ID -eq 7001){'Logon'} ElseIf($_.ID -eq 7002){ 'Logoff' } } },
    @{Name = 'User'; Expression = { [System.Security.Principal.SecurityIdentifier]::new( $_.Properties[1].Value ).Translate([System.Security.Principal.NTAccount]) } }

在您的情况下,这应该向对象添加一个名为 User 的属性,其值类似于 DomainName\UserName。我还添加了表达式来派生您添加到自定义对象的其他属性。 Select-Object也会发出自定义对象,因此这应该会给出您正在寻找的结果。

让我知道这是否有帮助。

更新

恭敬地,其他 2 个答案假设您正在寻找特定用户的登录/关闭事件。这不是我阅读问题的方式;尤其是:

“获取所有登录/退出服务器的用户”

虽然 PowerShell 7+ 确实允许您在 FilterHashtable 中直接引用 UserID,但它在这里并不是很有用,因为我们不是在寻找特定用户的事件。此外,它似乎对最终输出没有帮助,因为默认情况下它会作为 SID 回显。它仍然需要翻译,不仅是为了显示,而且是为了进一步过滤。我也不肯定 UserID 将始终与 相同Properties[1],在查看其他事件 ID 时肯定会有一些差异。

XML 工作非常酷,但我认为这里不需要它。

我的回答也有一些问题。我忽略了预先过滤事件 ID 和日期。我还意识到我们不需要实例化[System.Security.Principal.SecurityIdentifier]类,因为该属性已经是这样输入的。除了一些可读性改进之外,我还纠正了以下这些问题。

# Should be the 1st line!
using NameSpace System.Security.Principal

$ResolveEventType = @{ 7001 = 'Logon'; 7002 = 'Logoff' }
$FilterHashTable  =
    @{
        LogName      = 'system'
        ProviderName = 'Microsoft-Windows-Winlogon'
        ID           = 7001,7002
        StartTime    = (Get-Date).AddDays(-7)
    }

[Array]$WinEvents = 
Get-WinEvent -FilterHashtable $FilterHashTable | 
Select-Object @{ Name = 'Time'; Expression = { $_.TimeCreated } },
    @{ Name = 'Event'; Expression = { $ResolveEventType[ $_.ID ] } },
    @{ Name = 'User'; Expression = { $_.Properties[1].Value.Translate( [NTAccount] ) } }

$WinEvents | 
Where-Object{ $_.UserName -notlike "*-organization" } | 
Format-Table -AutoSize

这在 PowerShell 5.1 和 7.0 中测试良好。我添加Format-Table以显示输出,但您可以Export-Csv根据需要将其更改为命令

注意:最后 2 个管道可以组合,但我认为这更具可读性。

让我知道这是否有帮助。

于 2020-07-24T19:39:22.523 回答