Repository: PowerShell/PowerShell
File: src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs (C#)

Code before:

            try
            {
                int error;
                if (!Win32Native.OpenProcessToken(process.Handle, TOKEN_QUERY, out processTokenHandler))
                {
                    return null;
                }

                // Set the default length to be 256, so it will be sufficient for most cases.
                int tokenInfoLength = 256;
                tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength);
                if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength))
                {
                    error = Marshal.GetLastWin32Error();
                    if (error == Win32Native.ERROR_INSUFFICIENT_BUFFER)
                    {
                        Marshal.FreeHGlobal(tokenUserInfo);
                        tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength);

                        if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength))
                        {
                            return null;
                        }
                    }
                    else
                    {
                        return null;
                    }
                }

                var tokenUser = Marshal.PtrToStructure<Win32Native.TOKEN_USER>(tokenUserInfo);

                // Max username is defined as UNLEN = 256 in lmcons.h
                // Max domainname is defined as DNLEN = CNLEN = 15 in lmcons.h
                // The buffer length must be +1, last position is for a null string terminator.
                int userNameLength = 257;
                int domainNameLength = 16;
                Span<char> userNameStr = stackalloc char[userNameLength];
                Span<char> domainNameStr = stackalloc char[domainNameLength];
                Win32Native.SID_NAME_USE accountType;

                // userNameLength and domainNameLength will be set to actual lengths.
                if (!Win32Native.LookupAccountSid(null, tokenUser.User.Sid, userNameStr, ref userNameLength, domainNameStr, ref domainNameLength, out accountType))
                {
                    return null;
                }

                userName = string.Concat(domainNameStr.Slice(0, domainNameLength), "\\", userNameStr.Slice(0, userNameLength));
            }
            catch (NotSupportedException)

Review comment (bug):
Is `sid.Value` going to be null when `sid.Translate` fails?

Code after:
                    error = Marshal.GetLastWin32Error();
                    if (error == Win32Native.ERROR_INSUFFICIENT_BUFFER)
                    {
                        Marshal.FreeHGlobal(tokenUserInfo);
                        tokenUserInfo = Marshal.AllocHGlobal(tokenInfoLength);

                        if (!Win32Native.GetTokenInformation(processTokenHandler, Win32Native.TOKEN_INFORMATION_CLASS.TokenUser, tokenUserInfo, tokenInfoLength, out tokenInfoLength))
                        {
                            return null;
                        }
                    }
                    else
                    {
                        return null;
                    }
                }

                var tokenUser = Marshal.PtrToStructure<Win32Native.TOKEN_USER>(tokenUserInfo);
                SecurityIdentifier sid = new SecurityIdentifier(tokenUser.User.Sid);
                userName = sid.Translate(typeof(System.Security.Principal.NTAccount)).Value;
            }
            catch (NotSupportedException)
            {
                // The Process not started yet, or it's a process from a remote machine.
            }
            catch (IdentityNotMappedException)
            {
                // SID cannot be mapped to a user
            }
            catch (InvalidOperationException)
            {
                // The Process has exited, Process.Handle will raise this exception.
            }
            catch (Win32Exception)
            {
                // We might get an AccessDenied error.
            }
            catch (Exception)
            {
                // I don't expect to get other exceptions.
            }
            finally
            {
                if (tokenUserInfo != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(tokenUserInfo);
                }

                if (processTokenHandler != IntPtr.Zero)
                {
                    Win32Native.CloseHandle(processTokenHandler);