Easier way to parse 'query user' in PowerShell

孤街醉人 提交于 2020-06-25 00:11:08

问题


I currently have the following query in PowerShell:

query user /server:$server

Which returns output:

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

Currently, I'm using @(query user /server:$server).Count - 1 as a value to represent the number of users logged on (it's not pretty, I know). However now I would like to obtain information such as USERNAME, ID, and LOGON TIME to use in other parts of my script.

My question is surrounding an easier way to parse the information above, or maybe a better solution to my problem all together: Counting and gathering information related to logged on users.

I've found other solutions that seem to work better, but I'm sure there's got to be a simpler way to accomplish this task:

$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 
    { 

    }

回答1:


Awesome references in the comments, and still open to more answers for this question as it should have an easier solution!

    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
    }
}

This solution solves the problem for now, kind of sloppy.

For more in-depth solutions with more functionalities, check the comments on the original question :)




回答2:


Old question, but it seems a workable solution:

(query user) -split "\n" -replace '\s\s+', ';' | convertfrom-csv -Delimiter ';'

This chunks the output into lines, as the answer above does, but then replaces more than one white space character (\s\s+) with a semi-colon, and then converts that output from csv using the semi-colon as a delimiter.

The reason for more than one white space is that the column headers have spaces in them (idle time, logon time), so with just one space it would try to interpret that as multiple columns. From the output of the command, it looks as if they always preserve at least 2 spaces between items anyway, and the logon time column also has spaces in the field.




回答3:


For gathering information.

based on https://ss64.com/nt/query-user.html

$result  = &quser
$result -replace '\s{2,}', ',' | ConvertFrom-Csv



回答4:


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



回答5:


My own column based take. I'm not sure how much the ID column can extend to the left. Not sure how wide the end is.

# q.ps1
quser | select -skip 1 | foreach { 
  $result = $_ -match '.(.{22})(.{18})(.{5})(.{8})(.{11})(.{17,18})'    

  [pscustomobject] @{
    USERNAME = $matches[1].trim()
    SESSIONNAME = $matches[2].trim()
    ID = [int]$matches[3].trim()
    STATE = $matches[4].trim()
    IdleTime = $matches[5].trim()
    LogonTime = [datetime]$matches[6].trim()
  }
}

Invoke-command example. This is good if you're using Guacamole.

$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



回答6:


I Further appended the above code to properly format and also consider the Disconnected users

$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
}


来源:https://stackoverflow.com/questions/39212183/easier-way-to-parse-query-user-in-powershell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!