Powershell 脚本查看当前登录的用户(域和计算机)+状态(活动、空闲、离开)

问题描述 投票:0回答:11

我正在寻找一个简单的命令来查看服务器上登录的用户。 我知道这个:

Get-WmiObject -Class win32_computersystem

但这不会为我提供我需要的信息。 它返回: 领域 制造商 模型 名称(机器名称) 主要所有者姓名 总物理内存

我在 Windows 2012 服务器上运行 Powershell 3.0。

还有

Get-WmiObject Win32_LoggedOnUser -ComputerName $Computer | Select Antecedent -Unique

没有给我我需要的确切答案。 我也很想看看空闲时间,或者他们是否活跃或不在。

powershell active-directory powershell-2.0 powershell-3.0 windows-server-2012
11个回答
146
投票

在寻找相同的解决方案时,我在 stackoverflow 中的另一个问题下找到了我需要的东西: Powershell-注销-远程会话。下面一行将返回登录用户的列表。

query user /server:$SERVER

34
投票

由于我们处于 PowerShell 区域,如果我们可以返回正确的 PowerShell 对象,那就特别有用......

我个人喜欢这种解析方法,因为简洁:

((quser) -replace '^>', '') -replace '\s{2,}', ',' | ConvertFrom-Csv

注意:这不考虑断开连接(“光盘”)的用户,但如果您只想快速获取用户列表而不关心其余信息,则效果很好。我只是想要一个列表,并不关心它们当前是否已断开连接。

如果您确实关心其余数据,那就有点复杂了:

(((quser) -replace '^>', '') -replace '\s{2,}', ',').Trim() | ForEach-Object {
    if ($_.Split(',').Count -eq 5) {
        Write-Output ($_ -replace '(^[^,]+)', '$1,')
    } else {
        Write-Output $_
    }
} | ConvertFrom-Csv

我更进一步,在我的博客上给你一个非常干净的对象。

我最终将其制作成一个模块。


21
投票

没有“简单的命令”可以做到这一点。 您可以编写一个函数,也可以选择多个代码存储库中在线提供的函数。 我用这个:

function get-loggedonuser ($computername){

#mjolinor 3/17/10

$regexa = '.+Domain="(.+)",Name="(.+)"$'
$regexd = '.+LogonId="(\d+)"$'

$logontype = @{
"0"="Local System"
"2"="Interactive" #(Local logon)
"3"="Network" # (Remote logon)
"4"="Batch" # (Scheduled task)
"5"="Service" # (Service account logon)
"7"="Unlock" #(Screen saver)
"8"="NetworkCleartext" # (Cleartext network logon)
"9"="NewCredentials" #(RunAs using alternate credentials)
"10"="RemoteInteractive" #(RDP\TS\RemoteAssistance)
"11"="CachedInteractive" #(Local w\cached credentials)
}

$logon_sessions = @(gwmi win32_logonsession -ComputerName $computername)
$logon_users = @(gwmi win32_loggedonuser -ComputerName $computername)

$session_user = @{}

$logon_users |% {
$_.antecedent -match $regexa > $nul
$username = $matches[1] + "\" + $matches[2]
$_.dependent -match $regexd > $nul
$session = $matches[1]
$session_user[$session] += $username
}


$logon_sessions |%{
$starttime = [management.managementdatetimeconverter]::todatetime($_.starttime)

$loggedonuser = New-Object -TypeName psobject
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Session" -Value $_.logonid
$loggedonuser | Add-Member -MemberType NoteProperty -Name "User" -Value $session_user[$_.logonid]
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Type" -Value $logontype[$_.logontype.tostring()]
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Auth" -Value $_.authenticationpackage
$loggedonuser | Add-Member -MemberType NoteProperty -Name "StartTime" -Value $starttime

$loggedonuser
}

}

15
投票

也许你可以用

做点什么
get-process -includeusername

4
投票

如果您想找到交互式登录的用户,我在这里找到了一个很好的提示:https://p0w3rsh3ll.wordpress.com/2012/02/03/get-logged-on-users/(Win32_ComputerSystem 没有帮助我) )

$explorerprocesses = @(Get-WmiObject -Query "Select * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue)
If ($explorerprocesses.Count -eq 0)
{
    "No explorer process found / Nobody interactively logged on"
}
Else
{
    ForEach ($i in $explorerprocesses)
    {
        $Username = $i.GetOwner().User
        $Domain = $i.GetOwner().Domain
        Write-Host "$Domain\$Username logged on since: $($i.ConvertToDateTime($i.CreationDate))"
    }
}

2
投票

这是我基于 DarKalimHero 的建议的方法,仅选择 Explorer.exe 进程

Function Get-RdpSessions 
{
    param(
        [string]$computername 
    )

    $processinfo = Get-WmiObject -Query "select * from win32_process where name='explorer.exe'" -ComputerName $computername

    $processinfo | ForEach-Object { $_.GetOwner().User } | Sort-Object -Unique | ForEach-Object { New-Object psobject -Property @{Computer=$computername;LoggedOn=$_} } | Select-Object Computer,LoggedOn
}

2
投票

我编辑了 mjolinor 脚本来删除重复记录和虚拟帐户名称,例如系统、网络服务等
如果你想获得所有用户

function get-loggedonuser ($computername){

$regexa = '.+Domain="(.+)",Name="(.+)"$'
$regexd = '.+LogonId="(\d+)"$'

$logontype = @{
"0"="Local System"
"2"="Interactive" #(Local logon)
"3"="Network" # (Remote logon)
"4"="Batch" # (Scheduled task)
"5"="Service" # (Service account logon)
"7"="Unlock" #(Screen saver)
"8"="NetworkCleartext" # (Cleartext network logon)
"9"="NewCredentials" #(RunAs using alternate credentials)
"10"="RemoteInteractive" #(RDP\TS\RemoteAssistance)
"11"="CachedInteractive" #(Local w\cached credentials)
}

$logon_sessions = @(gwmi win32_logonsession -ComputerName $computername)
$logon_users = @(gwmi win32_loggedonuser -ComputerName $computername)

$session_user = @{}

$logon_users |% {
$_.antecedent -match $regexa > $nul
$username = $matches[1] + "\" + $matches[2]
$_.dependent -match $regexd > $nul
$session = $matches[1]
$session_user[$session] += $username
}


$logon_sessions |%{
$starttime = [management.managementdatetimeconverter]::todatetime($_.starttime)
if ($session_user[$_.logonid] -notin $loggedonuser.user -and $session_user[$_.logonid] -notlike "*$*"){
$loggedonuser = New-Object -TypeName psobject
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Session" -Value $_.logonid
$loggedonuser | Add-Member -MemberType NoteProperty -Name "User" -Value $session_user[$_.logonid]
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Type" -Value $logontype[$_.logontype.tostring()]
$loggedonuser | Add-Member -MemberType NoteProperty -Name "Auth" -Value $_.authenticationpackage
$loggedonuser | Add-Member -MemberType NoteProperty -Name "StartTime" -Value $starttime

$loggedonuser
}
}

}

如果您只想拥有域用户

function get-loggedonuser ($computername){

    $HST= hostname
    $regexa = '.+Domain="(.+)",Name="(.+)"$'
    $regexd = '.+LogonId="(\d+)"$'
    
    $logontype = @{
    "0"="Local System"
    "2"="Interactive" #(Local logon)
    "3"="Network" # (Remote logon)
    "4"="Batch" # (Scheduled task)
    "5"="Service" # (Service account logon)
    "7"="Unlock" #(Screen saver)
    "8"="NetworkCleartext" # (Cleartext network logon)
    "9"="NewCredentials" #(RunAs using alternate credentials)
    "10"="RemoteInteractive" #(RDP\TS\RemoteAssistance)
    "11"="CachedInteractive" #(Local w\cached credentials)
    }
    
    $logon_sessions = @(Get-WmiObject win32_logonsession -ComputerName $computername)
    $logon_users = @(Get-WmiObject win32_loggedonuser -ComputerName $computername)
    
    $session_user = @{}
    
    $logon_users |ForEach-Object {
    $_.antecedent -match $regexa > $nul
    $username = $matches[1] + "\" + $matches[2]
    $_.dependent -match $regexd > $nul
    $session = $matches[1]
    $session_user[$session] += $username
    }
    
    
    $logon_sessions |ForEach-Object{
    if ($session_user[$_.logonid] -notin $loggedonuser.user -and $session_user[$_.logonid] -notlike "*$*" -and $session_user[$_.logonid] -notlike "*$HST*"){
    $loggedonuser = New-Object -TypeName psobject
    $loggedonuser | Add-Member -MemberType NoteProperty -Name "Session" -Value $_.logonid
    $loggedonuser | Add-Member -MemberType NoteProperty -Name "User" -Value $session_user[$_.logonid]
    $loggedonuser | Add-Member -MemberType NoteProperty -Name "Type" -Value $logontype[$_.logontype.tostring()]
    $loggedonuser | Add-Member -MemberType NoteProperty -Name "Auth" -Value $_.authenticationpackage
    $loggedonuser | Add-Member -MemberType NoteProperty -Name "StartTime" -Value $starttime
    
    $loggedonuser
    }
    }
    
    }

1
投票

另一个解决方案,也基于

query user
,但可以处理文化变化(据我所知)并产生强类型结果(即TimeSpan和DateTime值):

# Invoke "query user", it produces an output similar to this, but might be culture-dependant!
#
#  USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME
# >jantje                rdp-tcp#55          2  Active          .  3/29/2021 4:24 PM
#  pietje                                    4  Disc     49+01:01  4/14/2021 9:26 AM
$result = (&query 'user' | Out-String -Stream)

# Take the header text and insert a '|' before the start of every HEADER - although defined as inserting a bar after 
# every 2 or more spaces, or after the space at the start.
$fencedHeader = $result[0] -replace '(^\s|\s{2,})', '$1|'

# Now get the positions of all bars.
$fenceIndexes = ($fencedHeader | Select-String '\|' -AllMatches).Matches.Index

$timeSpanFormats = [string[]]@("d\+hh\:mm", "h\:mm", "m")
$entries = foreach($line in $result | Select-Object -Skip 1)
{
    # Insert bars on the same positions, and then split the line into separate parts using these bars.
    $fenceIndexes | ForEach-Object { $line = $line.Insert($_, "|") }
    $parts = $line -split '\|' | ForEach-Object { $_.Trim() }

    # Parse each part as a strongly typed value, using the UI Culture if needed.
    [PSCustomObject] @{
        IsCurrent   = ($parts[0] -eq '>');
        Username    = $parts[1];
        SessionName = $parts[2];
        Id          = [int]($parts[3]);
        State       = $parts[4];
        IdleTime    = $(if($parts[5] -ne '.') { [TimeSpan]::ParseExact($parts[5], $timeSpanFormats, [CultureInfo]::CurrentUICulture) } else { [TimeSpan]::Zero });
        LogonTime   = [DateTime]::ParseExact($parts[6], "g", [CultureInfo]::CurrentUICulture);
    }
}

# Yields the following result:
#
# IsCurrent Username SessionName Id State  IdleTime    LogonTime           
# --------- -------- ----------- -- -----  --------    ---------           
#      True jantje   rdp-tcp#32   2 Active 00:00:00    3/29/2021 4:24:00 PM
#     False pietje                4 Disc   48.11:06:00 4/14/2021 9:26:00 AM
$entries | Format-Table -AutoSize

1
投票

团队!

我有很好的解决方案来将本地会话获取为 [PSObject]。

Function Get-LocalSession {
<#
    .DESCRIPTION
        Get local session. Pasre output of command - 'query session'.
#>
    [OutputType([PSObject[]])]
    [CmdletBinding()]
    Param(
        
    )
    try {
        #region functions
        #endregion
        $Result = @()
        $Output = . query.exe 'session' | select-object -skip 1

        #use regex to parse
        $pattern = '^(?<This>.)(?<SessionName>[^\s]*)\s*(?<UserName>[a-z]\w*)?\s*(?<Id>[0-9]*)\s*(?<State>\w*)\s*((?<Type>\w*)\s*)?(?<Device>\w*)?'

        foreach ( $line in $output ){
            $match = [regex]::Matches( $line, $pattern )
            if ( $match ){
                $PSO = [PSCustomObject]@{
                    This        = $match[0].groups['This'].Value
                    SessionName = $match[0].groups['SessionName'].Value
                    UserName    = $match[0].groups['UserName'].Value
                    Id          = $match[0].groups['Id'].Value
                    State       = $match[0].groups['State'].Value
                    Type        = $match[0].groups['Type'].Value
                    Device      = $match[0].groups['Device'].Value
                }

                $Result += $PSO
            }
            Else {
                write-host "Unable to process line [$line] in function [Get-LocalSession]!"
            }
        }  
    }
    catch {
        #Get-ErrorReporting -Trap $PSItem
        write-host $PSItem
    }

    return $Result
}

#Run it

$SessionObject = Get-LocalSession
$SessionObject | format-table -autosize -property *



0
投票

这就是我刚刚想出来的,效果很好!

Get-Process -IncludeUserName | Select-Object -Unique | Where-Object {$_.UserName -notlike 'NT AUTHORITY\SYSTEM' -and $_.UserName -notlike 'NT AUTHORITY\NETWORK SERVICE' -and $_.UserName -notlike 'NT AUTHORITY\LOCAL SERVICE'} | Format-Table -Wrap -AutoSize

0
投票

mjolinor 答案的更新,使用

Get-CimInstance
而不是
Get-WMIObject

function Get-Sessions {
    
    # Adapted from https://stackoverflow.com/a/23220056/994622
    # Author: mjolinor
    # Modified by mmseng

    param(
        [string]$ComputerName = "localhost"
    )
    
    $logonTypes = @{
        "0" = "Local System"
        "2" = "Interactive" #(Local logon)
        "3" = "Network" # (Remote logon)
        "4" = "Batch" # (Scheduled task)
        "5" = "Service" # (Service account logon)
        "7" = "Unlock" #(Screen saver)
        "8" = "NetworkCleartext" # (Cleartext network logon)
        "9" = "NewCredentials" #(RunAs using alternate credentials)
        "10" = "RemoteInteractive" #(RDP\TS\RemoteAssistance)
        "11" = "CachedInteractive" #(Local w\cached credentials)
    }
    
    $logonSessions = @(Get-CimInstance -Class "win32_logonsession" -ComputerName $ComputerName)
    $logonUsers = @(Get-CimInstance -Class "win32_loggedonuser" -ComputerName $ComputerName)
    
    $sessionUsers = $logonUsers | ForEach-Object {
        $username = $_.Antecedent.Domain + "\" + $_.Antecedent.Name
        $_ | Add-Member -NotePropertyName "Username" -NotePropertyValue $username 
    }
    
    $logonSessions | ForEach-Object {
        $username = $sessionUsers | Where { $_.Dependent.LogonId -eq $_.LogonId } | Select -ExpandProperty "Username"
        $logonTypeFriendly = $logonTypes[$_.LogonType.ToString()]
        
        $_ | Add-Member -NotePropertyName "Username" -NotePropertyValue $username
        $_ | Add-Member -NotePropertyName "LogonTypeFriendly" -NotePropertyValue $logonTypeFriendly
        $_ | Add-Member -NotePropertyName "StartTimeFriendly" -NotePropertyValue $startTimeFriendly -PassThru
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.