Profile Property Stores

Go to Home Page

Starting with Vista, Windows employs many components who expose their data via IPropertyStores. shacct.dll contains the implementation of the property stores dealing with users and their profiles. These interfaces can only be retrived via CoCreateInstance, and not via any exported functions.


CLSID_LocalUserAccounts - 4F6BCD94-C2A5-42CE-8dbc-31e794be4630 - {0x4F6BCD94, 0xC2A5, 0x42CE, {0x8d, 0xbc, 0x31, 0xe7, 0x94, 0xbe, 0x46, 0x30}};
Tangible User Accounts
CLSID_LocalGroups - 8F3080A6-af99-4F2e-a806-f3d5702a0444 - {0x8F3080A6, 0xaf99, 0x4F2e, {0xa8, 0x06, 0xf3, 0xd5, 0x70, 0x2a, 0x04, 0x44}};
Computer resident groups (Administrators, Users, Guests, etc)
CLSID_LoggedOnAccounts - 987d8dfa-3e2c-4929-9c51-61ac8e00cbc3 - {0x987d8dfa, 0x3e2c, 0x4929, {0x9c, 0x51, 0x61, 0xac, 0x8e, 0x00, 0xcb, 0xc3}};
Accounts logged on to the computer now
CLSID_ProfileAccounts - 99CDC6E0-DA00-4DFA-8eb8-831d774f8891 - {0x99CDC6E0, 0xDA00, 0x4DFA, {0x8e, 0xb8, 0x83, 0x1d, 0x77, 0x4f, 0x88, 0x91}};
Accounts with a profile directory (including LocalSystem, LocalService, NetworkService)
CLSID_UserAccounts - C3C39131-B182-4801-b437-6d1e65b72f57 - {0xC3C39131, 0xB182, 0x4801, {0xb4, 0x37, 0x6d, 0x1e, 0x65, 0xb7, 0x2f, 0x57}};
Aggregates the info in CLSID_LocalUserAccounts and CLSID_ProfileAccounts


Each of the clsid's above implement only the IComputerAccounts interface. The ancillary interfaces are documented further down the page

IComputerAccounts : public IUnknown
    // 0xc - retrives an interface to enumerate the members
    // of the user/group collection specified by the CLSID above
    STDMETHOD(GetEnumerator)(IEnumAccounts** pEnumerator) = 0;

    // 0x10 - number of property stores/entries in this collection
    STDMETHOD(GetCount)(ULONG* pCount) = 0;

    // 0x14 - Get the user/profile property store at index
    STDMETHOD(GetAt)(ULONG index, IPropertyStore** ppPropStore) = 0;

    // 0x18 - resets the object state to default
    STDMETHOD(Reset)(void) = 0;

    // 0x1c - Create a new permanent user and return its propstore
    // E_NOTIMPL for logged on users
    STDMETHOD(Create)(PCWSTR pName, IPropertyStore** ppPropStore) = 0;

    // 0x20 - Deletes a permanent user using the RID in the prop store
    STDMETHOD(Delete)(IPropertyStore* pPropStore) = 0;

    // 0x24 - Retrieve a property store using a user or groups display name
    // E_NOTIMPL for CLSID_ProfileAccounts, must use FindByRid
    STDMETHOD(FindByName)(PCWSTR pUserName, IPropertyStore** ppPropStore) = 0;

    // 0x28 - Retrieve a prop store using the user or account rid
    // The rid is the last subauthority in a SID as in
    // rid = *GetSidSubAuthority((*GetSidSubAuthorityCount(pAccountSid)) - 1)
    STDMETHOD(FindByRid)(ULONG rid, IPropertyStore** ppPropStore) = 0;

    // 0x2c - interface is IComputerAccountNotify
    // The passed interface is added to the IGlobalInterfaceTable
    // Requires Administrator or you'll get access denied (0xD0000022)
    STDMETHOD(Advise)(IComputerAccountNotify* pCompAcctNotify, DWORD* pToken) = 0;

    // 0x30 - stop receiving account events
    STDMETHOD(Unadvise)(DWORD token) = 0;

Property Keys

All property keys except one contain the same GUID as the key, using only the pid of the PROPERTYKEY structure to differentiate. Not all property stores returned by the various CLSID implementations can query all the keys, some of these are noted in the table.

The prefix guid for all prop keys is GUID_AccPropPrefix = {0x705D8364, 0x7547, 0x468c, {0x8c, 0x88, 0x84, 0x86, 0x0b, 0xcb, 0xed, 0x4c}}

Name & DefinitionVariant Type/Notes
PKEY_SAM_Name = {GUID_AccPropPrefix, 2}LPWSTR
PKEY_SAM_PasswordLastSet = {GUID_AccPropPrefix, 5}FILETIME
PKEY_SAM_DateAccountExpires = {GUID_AccPropPrefix, 6}DATE
PKEY_SAM_PasswordCanChange = {GUID_AccPropPrefix, 7}FILETIME
PKEY_SAM_PasswordMustChange = {GUID_AccPropPrefix, 8}DATE
PKEY_SAM_FullName = {GUID_AccPropPrefix, 9}LPWSTR
PKEY_SAM_HomeDirectory = {GUID_AccPropPrefix, 10}LPWSTR
PKEY_SAM_HomeDirectoryDrive = {GUID_AccPropPrefix, 11}LPWSTR
PKEY_SAM_ScriptPath = {GUID_AccPropPrefix, 12}LPWSTR
PKEY_SAM_ProfilePath = {GUID_AccPropPrefix, 13}LPWSTR
PKEY_SAM_AdminComment = {GUID_AccPropPrefix, 14}LPWSTR
PKEY_SAM_Workstations = {GUID_AccPropPrefix, 15}Empty for no restriction or VT_LPWSTR | VT_VECTOR otherwise
(note the last entry in the array isn't null terminated on Win7, fixed in 8)
PKEY_SAM_UserComment = {GUID_AccPropPrefix, 16}LPWSTR
PKEY_SAM_Password = {GUID_AccPropPrefix, 17}LPWSTR - always an empty string
PKEY_SAM_SecurityID = {GUID_AccPropPrefix, 18}BLOB (PSID)
PKEY_SAM_UserAccountControl = {GUID_AccPropPrefix, 19}UI4 - LocalUserAccounts only. See here for flag definitions
PKEY_SAM_LogonHours = {GUID_AccPropPrefix, 20}VT_VECTOR | VT_UI1 - See here for a description of the format
PKEY_SAM_CountryCode = {GUID_AccPropPrefix, 21}VT_UI2
PKEY_SAM_CodePage = {GUID_AccPropPrefix, 22}VT_UI2
PKEY_SAM_PasswordExpired = {GUID_AccPropPrefix, 23}BOOL
PKEY_SAM_UserPicture = {GUID_AccPropPrefix, 24}BLOB - See the bottom of SHSetUserPicturePath for the data format
PKEY_SAM_PasswordHint = {GUID_AccPropPrefix, 25}LPWSTR
PKEY_SAM_Domain = {GUID_AccPropPrefix, 25}LPWSTR
PKEY_SAM_Groups = {GUID_AccPropPrefix, 31}LPWSTR - Always returns the string "Need to implement groups"
PKEY_SAM_Type = {GUID_AccPropPrefix, 32}UI4
PKEY_SAM_InteractiveLogin = {GUID_AccPropPrefix, 36}BOOL - This and the rest of the *Login values
test whether the user has the associated SE_*_LOGON_NAME right
PKEY_SAM_NetworkLogin = {GUID_AccPropPrefix, 37}BOOL
PKEY_SAM_BatchLogin = {GUID_AccPropPrefix, 38}BOOL
PKEY_SAM_ServiceLogin = {GUID_AccPropPrefix, 39}BOOL
PKEY_SAM_RemoteInteractiveLogin = {GUID_AccPropPrefix, 40}BOOL
PKEY_SAM_DenyInteractiveLogin = {GUID_AccPropPrefix, 41}BOOL
PKEY_SAM_DenyNetworkLogin = {GUID_AccPropPrefix, 42}BOOL
PKEY_SAM_DenyBatchLogin = {GUID_AccPropPrefix, 43}BOOL
PKEY_SAM_DenyServiceLogin = {GUID_AccPropPrefix, 44}BOOL
PKEY_SAM_DenyRemoteInteractiveLogin = {GUID_AccPropPrefix, 45}BOOL
PKEY_SAM_DontShowInLogonUI = {GUID_AccPropPrefix, 46}BOOL
PKEY_SAM_ShellAdminObjectProps = {GUID_AccPropPrefix, 47}?
PKEY_SAM_PasswordIsEmpty = {GUID_AccPropPrefix, 50}BOOL - only returns correct results when caller is an admin
PKEY_SAM_GroupMembers = {GUID_AccPropPrefix, 102}for groups only - VT_VECTOR | VT_VARIANT
(variants are VT_UNKNOWN, IPropertyStore* for each user in the group)
PKEY_SAM_ResidualID = {GUID_AccPropPrefix, 103}UI4 (RID part of SID)
PKEY_SAM_AccountIsDisabledForLogonUI =
{{0x8BF6B9F6, 0xb4f5, 0x482f, {0xa2, 0xc2, 0x44, 0xbd, 0xad, 0x2f, 0xcf, 0xa9}}, 51}
The nonstandard guid entry
GetValue returns E_INVALIDARG if not set, instead of returning a variant

LoggedOnAccounts Exclusive PROPERTYKEYs
Name & DefinitionVariant Type/Notes
PKEY_LOGON_LUID = {GUID_AccPropPrefix, 200}UI8
PKEY_LOGON_AuthenticationPackage = {GUID_AccPropPrefix, 201}LPWSTR - NTLM for example
PKEY_LOGON_TSSession = {GUID_AccPropPrefix, 202}UI4 - session id
PKEY_LOGON_LogonTime = {GUID_AccPropPrefix, 203}FILETIME
PKEY_LOGON_LogonServer = {GUID_AccPropPrefix, 204}LPWSTR - computer name
PKEY_LOGON_DnsDomainName = {GUID_AccPropPrefix, 205}LPWSTR
PKEY_LOGON_ClientName = {GUID_AccPropPrefix, 207}LPWSTR - value returned by WTSQuerySession(WTSClientName)
PKEY_LOGON_WinStationName = {GUID_AccPropPrefix, 208}LPWSTR
PKEY_LOGON_Status = {GUID_AccPropPrefix, 209}UI4 - a value from the WTS_CONNECTSTATE_CLASS enum

ProfileAccounts Exclusive PROPERTYKEYs
Name & DefinitionVariant Type/Notes
PKEY_PROFILE_Path = {GUID_AccPropPrefix, 500}LPWSTR - User profile directory
PKEY_PROFILE_GUID = {GUID_AccPropPrefix, 501}GUID - profile guid

The property stores that contain these keys also support the documented IPersistSerializedPropStorage interface too.

Ancillary Interfaces

IEnumAccounts is used to enumerate the contained groups/accounts using the familiar enumerator interface method

IEnumAccounts : public IUnknown
    // pFetched is required
    STDMETHOD(Next)(ULONG celt, IPropertyStore** ppStore, ULONG* pFetched) = 0;

    STDMETHOD(Skip)(ULONG celt) = 0;

    STDMETHOD(Reset)(void) = 0;

    STDMETHOD(Clone)(IEnumAccounts** ppEnum) = 0;

The IComputerAccountNotify allows clients to be notified when a user or group is changed. No indications are given on what has changed as this information is unavailable from the internal notification system (SamRegisterObjectChangeNotification) which just sets an event.

IComputerAccountNotify : public IUnknown
    // called when there is a change (user info changed, member added to a group, etc)
    STDMETHOD(OnEvent)(void) = 0;

    // called in IComputerAccounts::Advise()
    // queries for the delay in milliseconds
    // between OnEvent calls, can be set to 0 for no delay
    STDMETHOD(GetMinimumTimeout)(DWORD* pdwTimeout) = 0;

Other Functionality

Alongside the profile property stores, shacct.dll also houses the default implementation of the IProfileNotify interface. This interface performs various tasks when users are created and deleted and when their profiles are loaded and unloaded.

IProfileNotify : public IUnknown
    // Creates the <username>.dat file in the "%ProgramData%\Microsoft\User Account Pictures" directory
    STDMETHOD(OnCreate)(PCWSTR pStringSid, PCWSTR unused1, ULONG unused2) = 0;

    // Deletes the <username>.dat file in the "%ProgramData%\Microsoft\User Account Pictures" directory
    // and removes the folder aces created by OnLoad()
    STDMETHOD(OnDelete)(PCWSTR pStringSid, PCWSTR unused1, ULONG unused2) = 0;

    // E_NOTIMPL - aliased to OnUnload in the disassembly because they both return the same

    // E_NOTIMPL
    STDMETHOD(OnUpgrade)(PCWSTR, PCWSTR, ULONG, int) = 0;

    // adds an access allowed ace to the FOLDERID_PublicDesktop
    // folder and FOLDERID_CommonStartMenu
    // If pStringSid is an Administrator sid
    // an additional FILE_DELETE_CHILD | DELETE ace is added to both folders
    STDMETHOD(OnLoad)(PCWSTR pStringSid, PCWSTR unused1, ULONG unused2, PSID pSid) = 0;

    // E_NOTIMPL
    STDMETHOD(OnUnload)(PCWSTR, PCWSTR, ULONG, int) = 0;
CLSID_ProfileNotificationHandler - 56EA1054-195-467f-be3b-a287c4b6ea - {0x56EA1054, 0x1959, 0x467f, {0xbe, 0x3b, 0xa2, 0x87, 0xc4, 0xb6, 0xea}};
Required to create the interface

User Account Control flags

// frmo NTSam.h in the WDK
#define USER_ACCOUNT_DISABLED                       (0x00000001)
#define USER_HOME_DIRECTORY_REQUIRED                (0x00000002)
#define USER_PASSWORD_NOT_REQUIRED                  (0x00000004)
#define USER_TEMP_DUPLICATE_ACCOUNT                 (0x00000008)
#define USER_NORMAL_ACCOUNT                         (0x00000010)
#define USER_MNS_LOGON_ACCOUNT                      (0x00000020)
#define USER_INTERDOMAIN_TRUST_ACCOUNT              (0x00000040)
#define USER_WORKSTATION_TRUST_ACCOUNT              (0x00000080)
#define USER_SERVER_TRUST_ACCOUNT                   (0x00000100)
#define USER_DONT_EXPIRE_PASSWORD                   (0x00000200)
#define USER_ACCOUNT_AUTO_LOCKED                    (0x00000400)
#define USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED        (0x00000800)
#define USER_SMARTCARD_REQUIRED                     (0x00001000)
#define USER_TRUSTED_FOR_DELEGATION                 (0x00002000)
#define USER_NOT_DELEGATED                          (0x00004000)
#define USER_USE_DES_KEY_ONLY                       (0x00008000)
#define USER_DONT_REQUIRE_PREAUTH                   (0x00010000)
#define USER_PASSWORD_EXPIRED                       (0x00020000)
#define USER_NO_AUTH_DATA_REQUIRED                  (0x00080000)
#define USER_PARTIAL_SECRETS_ACCOUNT                (0x00100000)
#define USER_USE_AES_KEYS                           (0x00200000)

Logon Hours

From ntsam.h

LogonHours is a bit map of valid logon times. Each bit represents a unique division in a week. The largest bit map supported is 1260 bytes (10080 bits), which represents minutes per week.
In this case the first bit (bit 0, byte 0) is Sunday, 00:00:00 - 00-00:59; bit 1, byte 0 is Sunday, 00:01:00 - 00:01:59, etc.