Private/Get-LoggedInUser.ps1

<#
.SYNOPSIS
    This function gets the current user sesions on a remote or local computer.
.DESCRIPTION
    This function uses quser.exe to get the current user sessions from a remote or local computer.
.PARAMETER ComputerName
    Use this paramter to specify the computer you want to run the command aganist using its name or IPAddress.
 
.EXAMPLE
    PS C:\> Get-LoggedInUser
 
    ComputerName UserName ID SessionType State ScreenLocked IdleTime
    ------------ -------- -- ----------- ----- ------------ --------
    DESKTOP-D7FU4K5 pwsh.cc 1 DirectLogon Active False 0
 
    This examples gets the logged in users of the local computer.
.EXAMPLE
    Get-LoggedInUser -ComputerName $env:COMPUTERNAME,dc01v
 
    ComputerName UserName ID SessionType State ScreenLocked IdleTime
    ------------ -------- -- ----------- ----- ------------ --------
    DESKTOP-D7FU4K5 pwsh.cc 1 DirectLogon Active False 0
    dc01v administrator 1 DirectLogon Active False 0
 
    This example gets the currently logged on users for the local computer and a remote computer called dc01v.
.INPUTS
    System.String
        You can pipe a string that contains the computer name.
.OUTPUTS
    AdminTools.LoggedInuser
        Outputs a custom powershell object
.NOTES
    Requires Admin
.LINK
    https://github.com/MrPig91/SysAdminTools/wiki/Get%E2%80%90LoggedInUser
#>

Function Get-LoggedInUser () {
    [CmdletBinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)]
        [Alias("CN", "Name", "MachineName")]
        [string[]]$ComputerName = $ENV:ComputerName
    )

    PROCESS {
        foreach ($computer in $ComputerName) {
            try {
                Write-Information "Testing connection to $computer" -Tags 'Process'
                if ($True) {
                    $Users = quser.exe /server:$computer 2>$null | Select-Object -Skip 1

                    if (!$?) {
                        Write-Information "Error with quser.exe" -Tags 'Process'
                        if ($Global:Error[0].Exception.Message -eq "") {
                            throw $Global:Error[1]
                        }
                        elseif ($Global:Error[0].Exception.Message -like "No User exists*") {
                            Write-Warning "No users logged into $computer"
                        }
                        else {
                            throw $Global:Error[0]
                        }
                    }
    
                    $LoggedOnUsers = foreach ($user in $users) {
                        [PSCustomObject]@{
                            PSTypeName        = "AdminTools.LoggedInUser"
                            ComputerName      = $computer
                            UserName          = (-join $user[1 .. 20]).Trim()
                            SessionName       = (-join $user[23 .. 37]).Trim()
                            SessionId         = [int](-join $user[38 .. 44])
                            State             = (-join $user[46 .. 53]).Trim()
                            IdleTime          = (-join $user[54 .. 63]).Trim()
                            LogonTime         = [datetime](-join $user[65 .. ($user.Length - 1)])
                            LockScreenPresent = $false
                            LockScreenTimer   = (New-TimeSpan)
                            SessionType       = "TBD"
                        }
                    }
                    try {
                        Write-Information "Using WinRM and CIM to grab LogonUI process" -Tags 'Process'
                        $LogonUI = Get-CimInstance -ClassName win32_process -Filter "Name = 'LogonUI.exe'" -ComputerName $Computer -Property SessionId, Name, CreationDate -OperationTimeoutSec 1 -ErrorAction Stop
                    }
                    catch {
                        Write-Information "WinRM is not configured for $computer, using Dcom and WMI to grab LogonUI process" -Tags 'Process'
                        $LogonUI = Get-WmiObject -Class win32_process -ComputerName $computer -Filter "Name = 'LogonUI.exe'" -Property SessionId, Name, CreationDate -ErrorAction Stop |
                        Select-Object name, SessionId, @{n = "Time"; e = { [DateTime]::Now - $_.ConvertToDateTime($_.CreationDate) } }
                    }
    
                    foreach ($user in $LoggedOnUsers) {
                        if ($LogonUI.SessionId -contains $user.SessionId) {
                            $user.LockScreenPresent = $True
                            $user.LockScreenTimer = ($LogonUI | Where-Object SessionId -EQ $user.SessionId).Time
                        }
                        if ($user.State -eq "Disc") {
                            $user.State = "Disconnected"
                        }
                        $user.SessionType = switch -wildcard ($user.SessionName) {
                            "Console" { "DirectLogon"; Break }
                            "" { "Unkown"; Break }
                            "rdp*" { "RDP"; Break }
                            default { "" }
                        }
                        if ($user.IdleTime -ne "None" -and $user.IdleTime -ne ".") {
                            if ($user.IdleTime -Like "*+*") {
                                $user.IdleTime = New-TimeSpan -Days $user.IdleTime.Split('+')[0] -Hours $user.IdleTime.Split('+')[1].split(":")[0] -Minutes $user.IdleTime.Split('+')[1].split(":")[1]
                            }
                            elseif ($user.IdleTime -like "*:*") {
                                $user.idleTime = New-TimeSpan -Hours $user.IdleTime.Split(":")[0] -Minutes $user.IdleTime.Split(":")[1]
                            }
                            else {
                                $user.idleTime = New-TimeSpan -Minutes $user.IdleTime
                            }
                        }
                        else {
                            $user.idleTime = New-TimeSpan
                        }
    
                        $user | Add-Member -Name LogOffUser -Value { logoff $this.SessionId /server:$($this.ComputerName) } -MemberType ScriptMethod
                        $user | Add-Member -MemberType AliasProperty -Name ScreenLocked -Value LockScreenPresent

                        Write-Information "Outputting user object $($user.UserName)" -Tags 'Process'
                        $user
                    } #foreach
                } #if ping
                else {
                    $ErrorRecord = [System.Management.Automation.ErrorRecord]::new(
                        [System.Net.NetworkInformation.PingException]::new("$computer is unreachable"),
                        'TestConnectionException',
                        [System.Management.Automation.ErrorCategory]::ConnectionError,
                        $computer
                    )
                    $PSCmdlet.WriteError($ErrorRecord)
                }
            } #try
            catch [System.Management.Automation.RemoteException] {
                if ($_.Exception.Message -like "*The RPC server is unavailable*") {
                    Write-Warning "quser.exe failed on $comptuer, Ensure 'Netlogon Service (NP-In)' firewall rule is enabled"
                    $PSCmdlet.WriteError($_)
                }
                else {
                    $PSCmdlet.WriteError($_)
                }
            }
            catch [System.Runtime.InteropServices.COMException] {
                Write-Warning "WMI query failed on $computer. Ensure 'Windows Management Instrumentation (WMI-In)' firewall rule is enabled."
                $PSCmdlet.WriteError($_)
            }
            catch {
                Write-Information "Unexpected error occurred with $computer"
                $PSCmdlet.WriteError($_)
            }
        } #foreach
    } #process
}