entfernt
Goto Top

Powershell Script Angemeldete User und ClientPC

Hallo zusammen,

ich habe online folgendes Script gefunden:

<#
.Synopsis
Queries a computer to check for interactive sessions

.DESCRIPTION
This script takes the output from the quser program and parses this to PowerShell objects

.NOTES   
Name: Get-LoggedOnUser
Author: Jaap Brasser
Version: 1.2.1
DateUpdated: 2015-09-23

.LINK
http://www.jaapbrasser.com

.PARAMETER ComputerName
The string or array of string for which a query will be executed

.EXAMPLE
.\Get-LoggedOnUser.ps1 -ComputerName server01,server02

Description:
Will display the session information on server01 and server02

.EXAMPLE
'server01','server02' | .\Get-LoggedOnUser.ps1  

Description:
Will display the session information on server01 and server02
#>
param(
    [CmdletBinding()] 
    [Parameter(ValueFromPipeline=$true,
               ValueFromPipelineByPropertyName=$true)]
    [string[]]$ComputerName = 'localhost'  
)
begin {
    $ErrorActionPreference = 'Stop'  
}

process {
    foreach ($Computer in $ComputerName) {
        try {
            quser /server:$Computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
                $CurrentLine = $_.Trim() -Replace '\s+',' ' -Split '\s'  
                $HashProps = @{
                    UserName = $CurrentLine
                    ComputerName = $Computer
                }

                # If session is disconnected different fields will be selected
                if ($CurrentLine[2] -eq 'Disc') {  
                        $HashProps.SessionName = $null
                        $HashProps.Id = $CurrentLine[1]
                        $HashProps.State = $CurrentLine[2]
                        $HashProps.IdleTime = $CurrentLine[3]
                        $HashProps.LogonTime = $CurrentLine[4..6] -join ' '  
                        $HashProps.LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join ' '  
                } else {
                        $HashProps.SessionName = $CurrentLine[1]
                        $HashProps.Id = $CurrentLine[2]
                        $HashProps.State = $CurrentLine[3]
                        $HashProps.IdleTime = $CurrentLine[4]
                        $HashProps.LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join ' '  
                }

                New-Object -TypeName PSCustomObject -Property $HashProps |
                Select-Object -Property UserName,ComputerName,State
            }
        } catch {
            New-Object -TypeName PSCustomObject -Property @{
                ComputerName = $Computer
                Error = $_.Exception.Message
            } | Select-Object -Property UserName,ComputerName,State
        }
    }
}

Das Script kommt von hier:
https://web.archive.org/web/20210118231433/https://gallery.technet.micro ...

Dieses Script gibt an welche User auf den vorher genannten Servern angemeldet bzw getrennt sind.
Das funktioniert auch super, aber ich würde gerne noch sehen wie der Rechner heißt, von dem der User kommt...
Hier ist das "ComputerName" leider nur der Server auf dem der User aktuell angemeldet ist.

Kannman dieses Script dazu unkompliziert anpassen ?

VG

Content-Key: 1719323925

Url: https://administrator.de/contentid/1719323925

Printed on: April 26, 2024 at 21:04 o'clock

Mitglied: 143611
143611 Jan 13, 2022 at 14:45:25 (UTC)
Goto Top
Moin,

das Script "mal eben kurz"/unkompliziert zu erweitern, ist nicht möglich, weil quser.exe keine Informationen zum Quell-Host liefert...

Vielleicht findet sich ja die ein oder andere Person, welche das Script um mehr als das Parsen des outputs ergänzt.
Viel Erfolg!

schleeke
Member: colinardo
Solution colinardo Jan 13, 2022, updated at Sep 12, 2023 at 09:30:11 (UTC)
Goto Top
Servus,
kann man mit dem String-Geparse von quser/qwinsta/query user &co. machen, aber wenn sich etwas mit nativen System-Funktionen auslesen bevorzuge ich das dann doch face-wink
param(
    [parameter(mandatory=$true)][ValidateNotNullOrEmpty()][string[]]$computers
)

Add-Type '  
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Net;

namespace WTS {
    public static class Sessions {
        public enum WTS_CONNECTSTATE_CLASS {
            WTSActive,
            WTSConnected,
            WTSConnectQuery,
            WTSShadow,
            WTSDisconnected,
            WTSIdle,
            WTSListen,
            WTSReset,
            WTSDown,
            WTSInit
        }
        public enum WTS_INFO_CLASS
        {
             WTSInitialProgram,
             WTSApplicationName,
             WTSWorkingDirectory,
             WTSOEMId,
             WTSSessionId,
             WTSUserName,
             WTSWinStationName,
             WTSDomainName,
             WTSConnectState,
             WTSClientBuildNumber,
             WTSClientName,
             WTSClientDirectory,
             WTSClientProductId,
             WTSClientHardwareId,
             WTSClientAddress,
             WTSClientDisplay,
             WTSClientProtocolType,
             WTSIdleTime,
             WTSLogonTime,
             WTSIncomingBytes,
             WTSOutgoingBytes,
             WTSIncomingFrames,
             WTSOutgoingFrames,
             WTSClientInfo,
             WTSSessionInfo
        }
        
        [StructLayout(LayoutKind.Sequential)]
        private struct WTS_CLIENT_ADDRESS
        {
            public uint AddressFamily;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
            public byte[] Address;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct WTS_SESSION_INFO_1 {
            public Int32 ExecEnvId;
            public WTS_CONNECTSTATE_CLASS State;
            public Int32 SessionId;
            [MarshalAs(UnmanagedType.LPStr)]
            public String pSessionName;
            [MarshalAs(UnmanagedType.LPStr)]
            public String pHostName;
            [MarshalAs(UnmanagedType.LPStr)]
            public String pUserName;
            [MarshalAs(UnmanagedType.LPStr)]
            public String pDomainName;
            [MarshalAs(UnmanagedType.LPStr)]
            public String pFarmName;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct WTS_CLIENT_DISPLAY {
            public int HorizontalResolution;
            public int VerticalResolution;
            public int ColorDepth;
        }

        [DllImport("wtsapi32.dll", SetLastError = true)]  
        static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);

        [DllImport("wtsapi32.dll")]  
        static extern void WTSCloseServer(IntPtr hServer);

        [DllImport("Wtsapi32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]  
        static extern int WTSEnumerateSessionsEx(IntPtr hServer, ref int pLevel, int Filter, ref IntPtr ppSessionInfo, ref int pCount);

        [DllImport("wtsapi32.dll", SetLastError = true)]  
        static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);

        [DllImport("wtsapi32.dll")]  
        static extern void WTSFreeMemory(IntPtr pMemory);

        public class TerminalSession {
            public int SessionId;
            public WTS_CONNECTSTATE_CLASS SessionState;
            public string Host;
            public string SessionName;
            public string UserName;
            public object RemoteHost;
            public string DomainName;
            public string FarmName;
            public int ClientHorizontalResolution;
            public int ClientVerticalResolution;
            public string ClientColorDepth;
        }

        public static List<TerminalSession> GetTSSessions(string Server = "") {  
            IntPtr server = IntPtr.Zero;
            List<TerminalSession> result = new List<TerminalSession>();
            if (Server != "") {  
                server = WTSOpenServer(Server);
            }
            try {

                IntPtr ppSessionInfo = IntPtr.Zero;
                Int32 count = 0;
                Int32 pLevel = 1;
                Int32 retval = WTSEnumerateSessionsEx(server, ref pLevel, 0, ref ppSessionInfo, ref count);
                Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO_1));
                Int64 current = (Int64)ppSessionInfo;
                IntPtr buffer;
                int strLen;
                Hashtable colordepths = new Hashtable() {{ 1, "4bit"},{ 2, "8bit"},{ 4, "16bit"},{ 8, "24bit"},{ 16, "15bit"},{ 24, "24bit"},{ 32, "32bit"}};  

                if (retval != 0) {
                    for (int i = 0; i < count; i++) {
                        WTS_SESSION_INFO_1 si = (WTS_SESSION_INFO_1)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO_1));
                        current += dataSize;
                        
                        // get remote host information
                        object remotehost = null;
                        if (WTSQuerySessionInformation(server,si.SessionId ,WTS_INFO_CLASS.WTSClientAddress, out buffer, out strLen) && strLen > 1){
                            WTS_CLIENT_ADDRESS c_address  = (WTS_CLIENT_ADDRESS)Marshal.PtrToStructure(buffer, typeof(WTS_CLIENT_ADDRESS));
                            if (c_address.AddressFamily == 2 && c_address.Address[2] != 0){
                                // AF_INET (IPv4 address)
                                remotehost = new IPAddress(new byte[] {c_address.Address[2],c_address.Address[3],c_address.Address[4],c_address.Address[5]});
                            } else if (c_address.AddressFamily == 23){
                                // AF_INET6 (IPv6 address)
                                byte[] bv6 = new byte[16];
                                Array.Copy(c_address.Address,2,bv6,0,16);
                                remotehost = new IPAddress(bv6);
                            } else {
                                remotehost = new IPAddress(new byte[] {0,0,0,0});
                            }
                            WTSFreeMemory(buffer);
                        }
                        // get remote display information
                        WTS_CLIENT_DISPLAY oClientDisplay = new WTS_CLIENT_DISPLAY();
                        if (WTSQuerySessionInformation(server,si.SessionId ,WTS_INFO_CLASS.WTSClientDisplay, out buffer, out strLen) && strLen > 1){
                            oClientDisplay = (WTS_CLIENT_DISPLAY)Marshal.PtrToStructure(buffer, oClientDisplay.GetType());
                            WTSFreeMemory(buffer);
                        }

                        result.Add(new TerminalSession() {
                            SessionId = si.SessionId,
                            SessionState = si.State,
                            SessionName = si.pSessionName,
                            Host = Server,
                            RemoteHost = remotehost,
                            UserName = si.pUserName,
                            DomainName = si.pDomainName,
                            FarmName = si.pFarmName,
                            ClientHorizontalResolution = oClientDisplay.HorizontalResolution, 
                            ClientVerticalResolution = oClientDisplay.VerticalResolution,
                            ClientColorDepth = (string)colordepths[oClientDisplay.ColorDepth]
                        });
                    }

                    WTSFreeMemory(ppSessionInfo);
                }
            }catch(Exception ex) {
                throw new Exception(ex.Message);
            } finally {
                WTSCloseServer(server);
            }
            return result;
        }
    }
}
'  
$computers | %{[WTS.Sessions]::GetTSSessions($_) | select Host,SessionId,SessionState,Sessionname,DomainName,Username,RemoteHost}
Grüße Uwe
Mitglied: 143611
143611 Jan 13, 2022 at 18:44:23 (UTC)
Goto Top
Sweet! 😁
Member: entfernt
entfernt Jan 14, 2022 at 10:59:27 (UTC)
Goto Top
Cool, vielen Dank schonmal.
Aber... :D Die Remotehosts nutzen mir leider als IP Adressen gar nichts, ich bräuchte hier tatsächlich den Hostname.

Ist das auch möglich ?

VG
Member: colinardo
colinardo Jan 14, 2022 updated at 11:17:05 (UTC)
Goto Top
Zitat von @geloescht:

Cool, vielen Dank schonmal.
Aber... :D Die Remotehosts nutzen mir leider als IP Adressen gar nichts, ich bräuchte hier tatsächlich den Hostname.

Ist das auch möglich ?

Klar löse den Hostname einfach reverse über den Pointer Eintrag deines DNS-Servers auf face-smile
[System.Net.Dns]::Resolve('1.1.1.1').Hostname  

Für das obige Skript ändere die letzte Zeile in
$computers | %{[WTS.Sessions]::GetTSSessions($_) | select Host,SessionId,SessionState,Sessionname,DomainName,Username,@{n='RemoteHost';e={if($_.RemoteHost -ne $null){[System.Net.Dns]::Resolve($_.RemoteHost).Hostname}}}}  
Dann bekommst du Hostnamen statt IPs, sofern dein DNS diese auch auflösen kann.
Member: entfernt
entfernt Jan 15, 2022 at 08:21:41 (UTC)
Goto Top
Absolut mega!

In Powershell war ich nie besonders erfahren aber bei dem Script blick ich ja gar nicht mehr durch ^^

Ich wollte eigentlich schauen ob ich es noch umbasteln kann, dass die Servernamen nicht als input abgefragt werden sondern ich sie gleich im Script angeben kann, praktisch: Server01, Server02, Server03 usw aber ich finde nicht einmal die Stelle wo die abgefragt werden. Bzw ich vermute das wird hier gemacht:
        public static List<TerminalSession> GetTSSessions(string Server = "") {  
            IntPtr server = IntPtr.Zero;
            List<TerminalSession> result = new List<TerminalSession>();
            if (Server != "") {  
                server = WTSOpenServer(Server);

Aber ich habe gar keine Idee wie ich das anpasse :D

VG
Member: colinardo
colinardo Jan 15, 2022 updated at 09:07:48 (UTC)
Goto Top
dass die Servernamen nicht als input abgefragt werden sondern ich sie gleich im Script angeben kann,
Ersetze nur das Parameter Konstrukt ganz am Anfang
param(
    [parameter(mandatory=$true)][ValidateNotNullOrEmpty()][string[]]$computers
)
durch
$computers = 'Server1','Server2'  
Done.