fredag den 4. marts 2011

Get username of process

So this is one more of those I hate WMI things. I needed to know the username of the owner of a process. As always I stumbled over

Public Shared Function GetProcessUserName(ByVal Process As Process) As String
    Dim sq As New ObjectQuery("Select * from Win32_Process Where ProcessID = '" & Process.Id & "'")
    Dim searcher As New ManagementObjectSearcher(sq)
    If searcher.Get.Count = 0 Then Return Nothing
    For Each oReturn As ManagementObject In searcher.Get
        Dim o As String() = New String(1) {}
        oReturn.InvokeMethod("GetOwner", DirectCast(o, Object()))
        Return o(1) & "\" & o(0)
    Next
    Return ""
End Function

it works, sure, but it isn't pretty and its WMI … did I mention I hate WMI ?

Friend Enum TOKEN_INFORMATION_CLASS
    TokenUser = 1
    TokenGroups
    TokenPrivileges
    TokenOwner
    TokenPrimaryGroup
    TokenDefaultDacl
    TokenSource
    TokenType
    TokenImpersonationLevel
    TokenStatistics
    TokenRestrictedSids
    TokenSessionId
    TokenGroupsAndPrivileges
    TokenSessionReference
    TokenSandBoxInert
    TokenAuditPolicy
    TokenOrigin
    TokenElevationType
    TokenLinkedToken
    TokenElevation
    TokenHasRestrictions
    TokenAccessInformation
    TokenVirtualizationAllowed
    TokenVirtualizationEnabled
    TokenIntegrityLevel
    TokenUIAccess
    TokenMandatoryPolicy
    TokenLogonSid
    MaxTokenInfoClass
End Enum

Public Structure TOKEN_USER
    Public User As SID_AND_ATTRIBUTES
End Structure

<StructLayout(LayoutKind.Sequential)> _
Public Structure SID_AND_ATTRIBUTES
    Public Sid As IntPtr
    Public Attributes As Integer
End Structure

<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Private Shared Function GetTokenInformation(ByVal hToken As IntPtr, ByVal tokenInfoClass As TOKEN_INFORMATION_CLASS, ByVal pTokenInfo As IntPtr, ByVal tokenInfoLength As Integer, <Out()> ByRef returnLength As Integer) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Shared Function GetProcessUserName(ByVal Process As Process) As String
    Dim hToken As IntPtr
    Try
        If (Not OpenProcessToken(Process.Handle, _
            TOKEN_QUERY, hToken)) Then
            'Throw New System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error)
            Return ""
        End If
    Catch ex As Exception
        'Throw ex
        Return ""
    End Try
    Dim tokenInfoSize As Integer = 250
    Dim userTokenInfo As IntPtr = Marshal.AllocHGlobal(CInt(tokenInfoSize))
    If GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser, userTokenInfo, tokenInfoSize, tokenInfoSize) Then
        Dim tokUser As TOKEN_USER = DirectCast(Marshal.PtrToStructure(userTokenInfo, GetType(TOKEN_USER)), TOKEN_USER)
        Dim a As New SecurityIdentifier(tokUser.User.Sid)
        Return a.Translate(GetType(NTAccount)).ToString
    End If
    Return False
End Function

I love it! and it almost use the same amount of code lines … *cough*

1 kommentar: