Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
更容易解析';查询用户';在PowerShell中_Powershell_Parsing_Scripting_Server_Powershell 3.0 - Fatal编程技术网

更容易解析';查询用户';在PowerShell中

更容易解析';查询用户';在PowerShell中,powershell,parsing,scripting,server,powershell-3.0,Powershell,Parsing,Scripting,Server,Powershell 3.0,我当前在PowerShell中有以下查询: query user /server:$server 它返回输出: USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME svc_chthost 2 Disc 1:05 8/16/2016 12:01 PM myusername rdp-t

我当前在PowerShell中有以下查询:

query user /server:$server
它返回输出:

USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME  
svc_chthost                               2  Disc         1:05  8/16/2016 12:01 PM  
myusername                rdp-tcp         3  Active          .  8/29/2016 11:29 AM
目前,我正在使用
@(查询用户/服务器:$server)。将-1
作为一个值来表示登录的用户数(我知道这并不漂亮)。但是,现在我想获得一些信息,如
用户名
ID
,以及
登录时间
,以便在脚本的其他部分使用

我的问题围绕着一种更简单的方法来解析上面的信息,或者可能是一种更好的解决方案:计算和收集与登录用户相关的信息

我找到了其他似乎效果更好的解决方案,但我相信一定有更简单的方法来完成这项任务:

$ComputerName | Foreach-object { 
$Computer = $_ 
try 
    {
        $processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer -EA "Stop") 
            if ($processinfo) 
            {     
                $processinfo | Foreach-Object {$_.GetOwner().User} |  
                Where-Object {$_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM"} | 
                Sort-Object -Unique | 
                ForEach-Object { New-Object psobject -Property @{Computer=$Computer;LoggedOn=$_} } |  
                Select-Object Computer,LoggedOn 
            }#If 
    } 
catch 
    { 

    }

评论中有很棒的参考资料,对于这个问题仍然有更多的答案,因为它应该有一个更简单的解决方案

    foreach ($s in $servers) #For Each Server
{
    foreach($ServerLine in @(query user /server:$s) -split "\n") #Each Server Line
    {
        #USERNAME              SESSIONNAME        ID  STATE   IDLE TIME  LOGON TIME

        $Parsed_Server = $ServerLine -split '\s+'

        $Parsed_Server[1] #USERNAME
        $Parsed_Server[2] #SESSIONNAME
        $Parsed_Server[3] #ID
        $Parsed_Server[4] #STATE
        $Parsed_Server[5] #IDLE TIME
        $Parsed_Server[6] #LOGON TIME
    }
}
这个解决方案现在解决了这个问题,有点草率


对于具有更多功能的更深入的解决方案,检查原始问题的注释:(

< P>),我进一步追加上述代码以正确地格式化,并考虑断开的用户

$HaSH = @()
foreach($ServerLine in @(query user) -split "\n")  {
    $Report = "" | Select-Object UserName, Session, ID, State, IdleTime, LogonTime
    $Parsed_Server = $ServerLine -split '\s+'
    if($Parsed_Server -like "USERNAME*") {
    Continue
    }
    $Report.UserName =  $Parsed_Server[1]
    $Report.Session = $Parsed_Server[2]
    $Report.ID = $Parsed_Server[3]
    $Report.State = $Parsed_Server[4]
    $Report.IdleTime = $Parsed_Server[5]
    $Report.LogonTime = $Parsed_Server[6]+" " +$Parsed_Server[7]+" "+$Parsed_Server[8]

    if($Parsed_Server[3] -eq "Disc") {
        $Report.Session = "None"
        $Report.ID = $Parsed_Server[2]
        $Report.State = $Parsed_Server[3]
        $Report.IdleTime = $Parsed_Server[4]
        $Report.LogonTime = $Parsed_Server[5]+" " +$Parsed_Server[6]+" "+$Parsed_Server[7]
    }

    if($Parsed_Server -like ">*") {
        $Parsed_Server=$Parsed_Server.Replace(">","")
        $Report.UserName =  $Parsed_Server[0]
        $Report.Session = $Parsed_Server[1]
        $Report.ID = $Parsed_Server[2]
        $Report.State = $Parsed_Server[3]
        $Report.IdleTime = $Parsed_Server[4]
        $Report.LogonTime = $Parsed_Server[5]+" " +$Parsed_Server[6]+" "+$Parsed_Server[7]
    }
    $HaSH+=$Report
}

这是一个老问题,但似乎是一个可行的解决方案:

(query user) -split "\n" -replace '\s\s+', ';' | convertfrom-csv -Delimiter ';'
与上面的答案一样,这会将输出分块成行,但随后会将多个空格字符(\s\s+)替换为分号,然后使用分号作为分隔符从csv转换该输出


之所以有多个空格,是因为列标题中有空格(空闲时间、登录时间),所以只要有一个空格,它就会试图将其解释为多个列。从命令的输出来看,它们似乎总是在项目之间至少保留2个空格,登录时间列的字段中也有空格。

用于收集信息

Function Get-QueryUser(){
Param([switch]$Json) # ALLOWS YOU TO RETURN A JSON OBJECT
    $HT = @()
    $Lines = @(query user).foreach({$(($_) -replace('\s{2,}',','))}) # REPLACES ALL OCCURENCES OF 2 OR MORE SPACES IN A ROW WITH A SINGLE COMMA
    $header=$($Lines[0].split(',').trim())  # EXTRACTS THE FIRST ROW FOR ITS HEADER LINE 
    for($i=1;$i -lt $($Lines.Count);$i++){ # NOTE $i=1 TO SKIP THE HEADER LINE
        $Res = "" | Select-Object $header # CREATES AN EMPTY PSCUSTOMOBJECT WITH PRE DEFINED FIELDS
        $Line = $($Lines[$i].split(',')).foreach({ $_.trim().trim('>') }) # SPLITS AND THEN TRIMS ANOMALIES 
        if($Line.count -eq 5) { $Line = @($Line[0],"$($null)",$Line[1],$Line[2],$Line[3],$Line[4] ) } # ACCOUNTS FOR DISCONNECTED SCENARIO
            for($x=0;$x -lt $($Line.count);$x++){
                $Res.$($header[$x]) = $Line[$x] # DYNAMICALLY ADDS DATA TO $Res
            }
        $HT += $Res # APPENDS THE LINE OF DATA AS PSCUSTOMOBJECT TO AN ARRAY
        Remove-Variable Res # DESTROYS THE LINE OF DATA BY REMOVING THE VARIABLE
    }
        if($Json) {
        $JsonObj = [pscustomobject]@{ $($env:COMPUTERNAME)=$HT } | convertto-json  # CREATES ROOT ELEMENT OF COMPUTERNAME AND ADDS THE COMPLETED ARRAY
            Return $JsonObj
        } else {
            Return $HT
        }
}


Get-QueryUser
  or
Get-QueryUser -Json
基于


我自己的专栏文章。我不确定ID列可以向左延伸多少。不知道末端有多宽。这是一个棘手的问题。也许这样更好:

调用命令示例。如果你用的是鳄梨酱,这很好

$c = get-credential
icm comp1,comp2,comp3 q.ps1 -cr $c | ft


USERNAME SESSIONNAME  ID STATE IdleTime LogonTime            PSComputerName RunspaceId
-------- -----------  -- ----- -------- ---------            -------------- ----------
js1                  136 Disc  .        6/20/2020 4:26:00 PM comp1          a8e670cd-4f31-4fd0-8cab-8aa11ee75a73
js2                  137 Disc  .        6/20/2020 4:26:00 PM comp2          a8e670cd-4f31-4fd0-8cab-8aa11ee75a74
js3                  138 Disc  .        6/20/2020 4:26:00 PM comp3          a8e670cd-4f31-4fd0-8cab-8aa11ee75a75

已编辑:看起来有人已经创建了一个实际运行良好的脚本:

真不敢相信这么多年后,仍然没有本地的PowerShell

我已经修改了Tyler Dickson所做的,并确保结果作为PSCustomObject返回

$Servers = @("10.x.x.x", "10.y.y.y")
$Result = @()
foreach ($Server in $Servers) {
    $Lines = @(query user /server:$s) -split "\n"

    foreach($Line in $Lines) #Each Server Line
    {
        if ($Line -match "USERNAME\s+SESSIONNAME\s+ID\s+STATE\s+IDLE TIME\s+LOGON TIME") {
            continue  # If is the header then skip to next item in array
        }

        $Parsed_Server = $Line -split '\s+'
        $Result += [PSCustomObject]@{
            SERVER = $Server
            USERNAME = $Parsed_Server[1]
            SESSIONNAME = $Parsed_Server[2]
            ID = $Parsed_Server[3]
            STATE = $Parsed_Server[4]
            IDLE_TIME = $Parsed_Server[5]
            LOGON_TIME = $Parsed_Server[6]
        }
    }
}

$Result | Format-Table
示例输出:

SERVER     USERNAME     SESSIONNAME ID STATE  IDLE_TIME LOGON_TIME
------     --------     ----------- -- -----  --------- ----------
10.x.x.x   user01       rdp-tcp#13  6  Active .         28/06/2020
10.x.x.x   user02       rdp-tcp#35  11 Active 59        29/06/2020
10.y.y.y   user03       rdp-tcp#38  12 Active .         29/06/2020
10.y.y.y   user04       rdp-tcp#43  14 Active 5         29/06/2020

我觉得有点奇怪,我找不到一个“纯Powershell”的解决方案。其他人花时间创建了一个脚本来完成您想要的任务,不过:也请参见:@poorkenny:一个纯Powershell解决方案可以使用Pinvoke调用WTSQuerySessionInformation(这需要大量代码,特别是对于PS纯粹主义者来说,他将使用.NET中的ModuleBuilder而不是嵌入C代码来创建此脚本).什么是“邋遢”,你想在这里换衣服吗?(试着在一条评论中总结一下,我们不会有太多允许的:-p-现在,我正试图从上面的评论中完善代码)只有
foreach(split){foreach(split){}
正在进行。我相信有一种更简单的方法来解析信息。老实说,这是我能想出的最好的解决方案,不会使解决方案过于复杂化。作为查询用户(quser)已经做了我想做的事情。我主要是在寻找一种管理输出的解决方案。你的解决方案和@Poorkenny的链接都很好,我只是对简短而甜蜜的解决方案很挑剔:P所以我想总结一下,这个解决方案不是太草率-我只是希望有一种更简单的方法将它们分类到可管理的对象中。@TylerDickson如果没有人连接到服务器,我发现你的解决方案有问题(假设是远程计算机),则SESSIONNAME可能为空,从而产生一个“间隙”,导致$Parsed_Server[2]是ID而不是[3];[3]是STATE而不是[4]…您看到解决方案了吗?虽然此代码可以回答此问题,但提供有关此代码为什么和/或如何回答此问题的其他上下文可提高其长期价值。
$Servers = @("10.x.x.x", "10.y.y.y")
$Result = @()
foreach ($Server in $Servers) {
    $Lines = @(query user /server:$s) -split "\n"

    foreach($Line in $Lines) #Each Server Line
    {
        if ($Line -match "USERNAME\s+SESSIONNAME\s+ID\s+STATE\s+IDLE TIME\s+LOGON TIME") {
            continue  # If is the header then skip to next item in array
        }

        $Parsed_Server = $Line -split '\s+'
        $Result += [PSCustomObject]@{
            SERVER = $Server
            USERNAME = $Parsed_Server[1]
            SESSIONNAME = $Parsed_Server[2]
            ID = $Parsed_Server[3]
            STATE = $Parsed_Server[4]
            IDLE_TIME = $Parsed_Server[5]
            LOGON_TIME = $Parsed_Server[6]
        }
    }
}

$Result | Format-Table
SERVER     USERNAME     SESSIONNAME ID STATE  IDLE_TIME LOGON_TIME
------     --------     ----------- -- -----  --------- ----------
10.x.x.x   user01       rdp-tcp#13  6  Active .         28/06/2020
10.x.x.x   user02       rdp-tcp#35  11 Active 59        29/06/2020
10.y.y.y   user03       rdp-tcp#38  12 Active .         29/06/2020
10.y.y.y   user04       rdp-tcp#43  14 Active 5         29/06/2020
$result = (&quser) -replace '\s{2,}', ',' | ConvertFrom-Csv | Select -ExpandProperty USERNAME
$loggedinuser = $result.Trim(">")