Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / F#

Parse quser.exe Results with Regex

5.00/5 (6 votes)
5 Jan 2017CPOL1 min read 19K  
Parse quser.exe Results in Regex in any .NET language

Introduction

This is a (Unix LR) Regular Expression to parse results from quser.exe, in any .NET language (including C#, F# and VB.NET).

(?m)^\s?(?<username>[\w\/.\/_\-]{2,64})\s\s+(?<sessionname>\w?.{0,22})\s\s+(?<sessionid>\d{1,5})\s\s+(?<state>.{0,12})\s\s+(?<idletime>.{0,20})\s\s+(?<logontime>.{0,32})$

Background

A recent project required the ability to remotely disconnect users (using logoff.exe, which requires a remote SessionID, which you can get from quser.exe). At the time of writing, the only other quser parser I've found is written for Powershell, and I wanted to use it inside of a .NET\WPF application without having to reference Powershell\System.Management assembly.

Tested on Windows 10, Server 2012 and Server 2008 R2.

Using the Code

I created the following sample, including a simple interface declaration, to hold our data.

Note that I've removed the multi-line flag (?m) from the above regular expression, in favor of .NET's RegexOptions.MultiLine enumeration. Here is a module for querying and parsing quser data:

F# Example

F#
namespace Vivrant.Parsers
    module QUser =
        open System
        open System.Diagnostics
        open System.Text.RegularExpressions
        type IQUserInformation =
            abstract member Username:String with get
            abstract member SessionName:String with get
            abstract member SessionID:String with get
            abstract member State:String with get
            abstract member IdleTime:String with get
            abstract member LogonTime:DateTime with get
        let QueryUsers(serverName:string) =
            let args = String.Format(" /SERVER:{0}", serverName)
            let cmdQuser = new Process()
            cmdQuser.StartInfo.WorkingDirectory <- Environment.CurrentDirectory
            cmdQuser.StartInfo.FileName <- "lib\quser.exe"
            cmdQuser.StartInfo.Arguments <- args
            cmdQuser.StartInfo.UseShellExecute <- false
            cmdQuser.StartInfo.RedirectStandardOutput <- true
            cmdQuser.StartInfo.CreateNoWindow <- true
            cmdQuser.Start()
            |> ignore
            let stdOut = cmdQuser.StandardOutput.ReadToEnd()
            while(not <| cmdQuser.HasExited) do
                    cmdQuser.WaitForExit()
            stdOut
        let ParseQUserResults(stdOut) =
            let userResults = new ResizeArray<IQUserInformation>()
            let quserPattern = @"^\s?(?<username>[\w\/.\/_\-]{2,64})\s\s+(?<sessionname>\w?.{0,22})\s\s+(?<sessionid>\d{1,5})\s\s+(?<state>.{0,12})\s\s+(?<idletime>.{0,20})\s\s+(?<logontime>.{0,32})$"
            let regex = new Regex(quserPattern, RegexOptions.Multiline)
            let mutable result = regex.Match(stdOut)
            while result.Success do
                    let success, parsedLogonTime = DateTime.TryParse(result.Groups.["logontime"].Value.ToString().Trim())
                    userResults.Add
                        { new IQUserInformation with
                            member this.Username = result.Groups.["username"].Value.ToString().Trim()
                            member this.SessionName = result.Groups.["sessionname"].Value.ToString().Trim()
                            member this.SessionID = result.Groups.["sessionid"].Value.ToString().Trim()
                            member this.State = result.Groups.["state"].Value.ToString().Trim()
                            member this.IdleTime = result.Groups.["idletime"].Value.ToString().Trim()
                            member this.LogonTime =
                                match success with
                                | true -> parsedLogonTime
                                | false -> DateTime.MinValue }
                    result <- result.NextMatch()
            userResults

Now we can call it like this:

F#
module Sample =
    let userInfo = QUser.ParseQUserResults <| QUser.QueryUsers "myPC"
    do ( ) //do something with userInfo

Points of Interest

Depending on your architecture (ie 32bit vs 64bit Processor, OS and Project Build settings), your application may not be able to see the file c:\Windows\system32\quser.exe, because Windows virtualizes access to the System directory.

In order for your program to see `quser.exe`, you may need to have a copy of it OUTSIDE of the SYSTEM32 folder. Browse to it in Explorer, copy, and paste it somewhere else. For the sake of this example, I placed it in a subfolder of my project folder, "MyProject\lib", and set the build options to "copy always".

History

  • 2016-12-13: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)