4

enter image description here

Trying to find out the active email / id of the user logged into Windows 8 with a Microsoft Account, assuming it is not a local account they are authenticated as.

  • Trying to find that out from a WPF desktop C# application, not a Windows Store app
  • Found the Live SDK to be potentially relevant, e.g. the me shortcut, but am not sure this API can be used from a full-fledged .NET application?
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Cel
  • 6,467
  • 8
  • 75
  • 110
  • Allowing apps to harvest email addresses was not a strong WinRT design goal. The registry is off limits, that won't pass the certification test. Even if it is possible, pretty doubtful, you still have to disclose this in your privacy statement. Not a great way to advertize your app. – Hans Passant May 31 '14 at 12:15

3 Answers3

8

Warning: undocumented behavior begins. this code can break any time Microsoft pushes a Windows Update.

when your user token is created a group named "Microsoft Account\YourAccountId" is added to the user token. You can use it to find the active user's Microsoft Account.

undocumented behavior ends

The API to list the current user's group names are :

  • OpenProcessToken GetCurrentProcess TOKEN_QUERY to get the process token
  • GetTokenInformation TokenGroups to get the groups in the token
  • LookupAccountSid to get group names

It is much easier to write an example using System.Security.Principal classes:

public static string GetAccoutName()
{
    var wi= WindowsIdentity.GetCurrent();
    var groups=from g in wi.Groups                       
               select new SecurityIdentifier(g.Value)
               .Translate(typeof(NTAccount)).Value;
    var msAccount = (from g in groups
                     where g.StartsWith(@"MicrosoftAccount\")
                     select g).FirstOrDefault();
    return msAccount == null ? wi.Name:
          msAccount.Substring(@"MicrosoftAccount\".Length);
}
Sheng Jiang 蒋晟
  • 15,125
  • 2
  • 28
  • 46
  • wow. any chance the first name and last name are in there somewhere as well? im trying to autopopulate the reviewer/commentator info of a kind of a text editor.. – Cel Jun 01 '14 at 10:08
  • I don't think so. You can try use the address with Windows Live Connect SDK to pull the name off Windows Live services. – Sheng Jiang 蒋晟 Jun 02 '14 at 07:20
0
  1. Open Registry Editor and navigate to:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

  2. Under the ProfileList key, you will see the SIDs. By selecting each one individually, you can look at the value entry and see what username is associated with that particular SID.

Sudhakar Tillapudi
  • 25,935
  • 5
  • 37
  • 67
  • this is not what im after im afraid (1) im looking for the Microsoft Account Id, which is a new feature of Windows 8 - e.g. the user is logged on as sudhakar.anothername@hotmail.co.uk (this is the id im after) (2) the registry keys you point to seem to list local accounts, which i could get with Environment.UserName i believe (giving me the active user as well, which is what im looking for) – Cel Nov 02 '13 at 11:14
  • Possible duplicate of http://stackoverflow.com/questions/7539593/log-in-to-desktop-application-by-windows-live-id, even though unflagable thanks to bounty – Kilazur May 31 '14 at 10:49
0

referring to the method described by Sheng (using tokens) here is a code on Delphi that we've created to get current MS account id:

function GetNameFromSid(ASid: Pointer): string;
var
  snu: SID_NAME_USE;

  szDomain, szUser : array [0..50] of Char;
  chDomain, chUser : Cardinal;
begin
    chDomain := 50;
    chUser   := 50;

    if LookupAccountSid(nil, ASID, szUser, chUser, szDomain, chDomain, snu) then
      Result := string(szDomain) + '\' + string(szUser);
end;

function GetUserGroups(AStrings: TStrings): Boolean;
var
  hAccessToken       : tHandle;
  ptgGroups          : pTokenGroups;
  dwInfoBufferSize   : DWORD;
  psidAdministrators : PSID;
  int                : integer;            // counter
  blnResult          : boolean;            // return flag

  ProcessId: Integer;
  hWindow, hProcess, TokenHandle: THandle;
  si: Tstartupinfo;
  p: Tprocessinformation;

const
  SECURITY_NT_AUTHORITY: SID_IDENTIFIER_AUTHORITY =
    (Value: (0,0,0,0,0,5)); // ntifs
  SECURITY_BUILTIN_DOMAIN_RID: DWORD = $00000020;
  DOMAIN_ALIAS_RID_ADMINS: DWORD = $00000220;
  DOMAIN_ALIAS_RID_USERS : DWORD = $00000221;
  DOMAIN_ALIAS_RID_GUESTS: DWORD = $00000222;
  DOMAIN_ALIAS_RID_POWER_: DWORD = $00000223;


begin
  Result := False;
  p.dwProcessId := 0;

  hWindow := FindWindow('Progman', 'Program Manager');
  GetWindowThreadProcessID(hWindow, @ProcessID);
  hProcess := OpenProcess (PROCESS_ALL_ACCESS, FALSE, ProcessID);
  if OpenProcessToken(hProcess, TOKEN_QUERY, TokenHandle) then
  begin
    GetMem(ptgGroups, 1024);
    try
      blnResult := GetTokenInformation( TokenHandle, TokenGroups,
                                        ptgGroups, 1024,
                                        dwInfoBufferSize );
      CloseHandle( TokenHandle );

      if blnResult then
      begin
        for int := 0 to ptgGroups.GroupCount - 1 do
          AStrings.Add(GetNameFromSid(ptgGroups.Groups[ int ].Sid));
      end;
    finally
      FreeMem( ptgGroups );
    end;
  end;
end;

function GetCurrnetMSAccoundId: string;
const
  msAccStr = 'MicrosoftAccount\';
var
  AGroups: TStrings;
  i: Integer;
begin
  Result := '';
  AGroups := TStringList.Create;
  try
    GetUserGroups(AGroups);
    for i := 0 to AGroups.Count-1 do
      if Pos(msAccStr, AGroups[i]) > 0 then
      begin
        Result := Copy(AGroups[i], Length(msAccStr)+1, Length(AGroups[i])-Length(msAccStr));
        Break;
      end;
  finally
    AGroups.Free;
  end;
end;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Alexander M.
  • 761
  • 1
  • 7
  • 14