её результат, но она не выводит домен юзера. Есть у кого нибудь аналог на поше или хотя бы в какой api тыкать можете подсказать?
https://www.powershellgallery.com/packages/PSReflect-Functions/1.1/Content/wtsapi32%5CWTSQuerySessionInformation.ps1
Есть, соль состоит том что парситься вывод quser'а, далее делается get-aduser с интересующими атрибутами..если get-aduser пустой значит юзер локальный
А если у нас 80 доменов?
Не поручусь на счёт результатов "WTSQuerySessionInformation", но выглядит правдоподобно. Вроде как, для данных целей NetWkstaUserEnum использовалась. Но там множество вариантов использовалось со своими особенностями.
Однозначно - крайне неудачный подход.
Не будьте столь однозначны ..говорю исключительно с точки зрения практики, а не теории которую не щупал..userEnum имеет свои "приколы".
Как вариант - можно через реестр извратиться, но я бы, пожалуй, не рекомендовал.
Ну, такой способ я предполагал, но поскольку формат модуля мне не подходит, то мне надо руками пересобрать это в отдельно работающий командлет. Я просто думал может быть у кого то есть что то готовое?
Постоянно следую данной рекомендации, но в данном случае вынужден отклониться по ряду причин.
Код открыт бери да переноси.
Так бы я и без вас справился.
Это и безумно медленно и ненадёжно и, как правильно подметили выше - у вас может быть огромный лес.
А чем именно не подходит данный формат?
Вот тут находится список всех ульев, загруженных в данный момент в реестр: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist Пользовательские имеют формат следующего вида: \REGISTRY\USER\%SID% Если так можно выразиться, прелесть в том, что не требуется никаких особых знаний и привилегий чтоб это прочесть.
Вот это судя по всему топчик. Сча буду собирать
В любом лесу есть глобальный каталог? Подводный камень предложенный из gallery работает только для терминальных серверов(или даже опубликованных RD - могу огибаться пару лет назад тестировал), для локально вошедших оно тоже не применимо..так что придётся делать компиляцию из всего если нужна подробная инфомация
Конечно есть, но это не делает подход адекватным в моём понимании. Например, как быть со случаем когда пользователь "Вася ГусеФ" может существовать в двух доменах и ещё и в качестве локального пользователя на машине?
У вас там в каком виде это запускаться будет?
Есть скрипт, который преобразовывает вывод quser в читаемый вид (в виде массива), если его немного допилить, то можно и домен пользователя дописать в отдельное свойство, взяв его из \HKEY_USERS\S-1-5-21-570079237-2135344701-1905390631-29901\Volatile Environment Если нужно, могу скинуть в личку
Сделал эту хрень. Короче, она кучу дублей выдаёт и session id не показывает. Буду переделывать на функции из Wtsapi32.dll
В общем, сговнякал тут рабочий набросок. Для начала, подготовительная обвязка: #################################################################################################### Add-Type -Language "CSharp" -TypeDefinition @" using System; using System.Runtime.InteropServices; namespace PInvoke { [StructLayout(LayoutKind.Explicit)] public struct Int64Value { [FieldOffset(0)] public Int64 Value; [FieldOffset(0)] public UInt32 Low; [FieldOffset(4)] public Int32 High; } public enum SECURITY_LOGON_TYPE : uint { UndefinedLogonType = 0, Interactive = 2, Network, Batch, Service, Proxy, Unlock, NetworkCleartext, NewCredentials, RemoteInteractive, CachedInteractive, CachedRemoteInteractive, CachedUnlock } public struct LUID { public UInt32 LowPart; public Int32 HighPart; } public struct LSA_LAST_INTER_LOGON_INFO { public UInt64 LastSuccessfulLogon; public UInt64 LastFailedLogon; public UInt32 FailedAttemptCountSinceLastSuccessfulLogon; } public struct LSA_UNICODE_STRING { public UInt16 Length; public UInt16 MaximumLength; public IntPtr Buffer; } public struct SECURITY_LOGON_SESSION_DATA { public UInt32 Size; public LUID LogonId; public LSA_UNICODE_STRING UserName; public LSA_UNICODE_STRING LogonDomain; public LSA_UNICODE_STRING AuthenticationPackage; public SECURITY_LOGON_TYPE LogonType; public UInt32 Session; public IntPtr Sid; public UInt64 LogonTime; public LSA_UNICODE_STRING LogonServer; public LSA_UNICODE_STRING DnsDomainName; public LSA_UNICODE_STRING Upn; public UInt32 UserFlags; public LSA_LAST_INTER_LOGON_INFO LastLogonInfo; public LSA_UNICODE_STRING LogonScript; public LSA_UNICODE_STRING ProfilePath; public LSA_UNICODE_STRING HomeDirectory; public LSA_UNICODE_STRING HomeDirectoryDrive; public UInt64 LogoffTime; public UInt64 KickOffTime; public UInt64 PasswordLastSet; public UInt64 PasswordCanChange; public UInt64 PasswordMustChange; } public class Secur32 { [DllImport("Secur32", SetLastError = true, CharSet = CharSet.Auto)] public static extern UInt32 LsaEnumerateLogonSessions( out UInt32 LogonSessionCount, out IntPtr LogonSessionList ); [DllImport("Secur32", SetLastError = true, CharSet = CharSet.Auto)] public static extern UInt32 LsaGetLogonSessionData( IntPtr LogonId, out IntPtr ppLogonSessionData ); [DllImport("Secur32", SetLastError = true, CharSet = CharSet.Auto)] public static extern UInt32 LsaFreeReturnBuffer( IntPtr Buffer ); } } "@ ####################################################################################################
А дальше уже сам процесс: [System.UInt32] $NTSTATUS = 0 [System.UInt64] $LogonSessionCount = 0 [System.IntPtr] $LogonSessionList = [System.IntPtr]::Zero $NTSTATUS = [PInvoke.Secur32]::LsaEnumerateLogonSessions([ref] $LogonSessionCount, [ref] $LogonSessionList) $iLUIDSize = [Runtime.InteropServices.Marshal]::SizeOf([System.Type] [PInvoke.LUID]) [System.IntPtr] $LogonSessionData = [System.IntPtr]::Zero $colLogonSessions = New-Object -TypeName System.Collections.ArrayList for ($iIndex = 0; $iIndex -lt $LogonSessionCount; $iIndex++) { $NTSTATUS = [PInvoke.Secur32]::LsaGetLogonSessionData($LogonSessionList, [ref] $LogonSessionData) $objLogonSessionData = [System.Runtime.InteropServices.Marshal]::PtrToStructure($LogonSessionData, [System.Type] [PInvoke.SECURITY_LOGON_SESSION_DATA]) $objSID = try {New-Object -TypeName System.Security.Principal.SecurityIdentifier($objLogonSessionData.Sid)} catch {"Her ego znaet!"} $iLogonId = New-Object -TypeName PInvoke.Int64Value $iLogonId.Low = $objLogonSessionData.LogonId.LowPart $iLogonId.High = $objLogonSessionData.LogonId.HighPart $hshLogonSession = @{ "LogonId" = $iLogonId.Value "UserName" = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($objLogonSessionData.UserName.Buffer, $objLogonSessionData.UserName.Length / 2) "LogonDomain" = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($objLogonSessionData.LogonDomain.Buffer, $objLogonSessionData.LogonDomain.Length / 2) "AuthenticationPackage" = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($objLogonSessionData.AuthenticationPackage.Buffer, $objLogonSessionData.AuthenticationPackage.Length / 2) "LogonType" = $objLogonSessionData.LogonType "Session" = $objLogonSessionData.Session "Sid" = $objSID "DnsDomainName" = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($objLogonSessionData.DnsDomainName.Buffer, $objLogonSessionData.DnsDomainName.Length / 2) "Upn" = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($objLogonSessionData.Upn.Buffer, $objLogonSessionData.Upn.Length / 2) } $null = $colLogonSessions.Add((New-Object -TypeName PSObject -Property $hshLogonSession)) $NTSTATUS = [PInvoke.Secur32]::LsaFreeReturnBuffer($LogonSessionData) $LogonSessionList = $LogonSessionList.ToInt64() + $iLUIDSize } $NTSTATUS = [PInvoke.Secur32]::LsaFreeReturnBuffer($LogonSessionList)
Ну и, как я сказал - это просто набросок для целей демонстрации, так что обработка ошибок отсутствует.
По сути - это тоже не он;).
Но хотя бы без вызова внешних программ. Я, кстати, переписал на чистый дотнет без C# вставок, а то я считаю, что вставки C# кода это не канонично.
Вечером покажу
Этот вариант только имя локального пользователя выводит.
На вкладке "Сведения" в обрезанном виде
Всё больше подобного рода извраты.
Скорее, тот же .NET.
У вас, кстати, вечер когда наступает:)?
Обсуждают сегодня