В HKEY_USERS находятся вошедшие пользователи и системные учётки (System, LocalService, NetworkService), от лица которых запущена пачка процессов/сервисов.
Стоит ещё помнить, что
HKEY_CURRENT_USER - отображение HKEY_USERS\<SID текущего пользователя>
HKEY_CURRENT_USER\Software\Classes - отображение HKEY_USERS\<SID текущего пользователя>_Classes
HKEY_CLASSES_ROOT -
объединённое отображение HKEY_CURRENT_USER\Software\Classes и HKEY_LOCAL_MACHINE\Software\Classes
перечисление пользователей с помощью NetQueryDisplayInformation
Код:
![Выделить весь код](images/misc/selectcode.png)
!include EnumUsersRegEx.nsh
RequestExecutionLevel user
ShowInstDetails show
; SetFont 'Fira Code Retina' 9
SetFont 'Consolas' 9
InstallColors /windows
; ChangeUI all "${MYNSISDIREXAMPLES}\Contrib\UIs\largelog.exe"
; https://learn.microsoft.com/en-us/windows/win32/secauthz/well-known-sids
; https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netquerydisplayinformation
; https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/ns-lmaccess-net_display_user
; https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netusergetinfo
!define GetUserSID `!insertmacro GetUserSID `
!macro GetUserSID outSID username
${If} '${username}' != ''
Push '${username}'
Exch $0 ; [in] username / [out] outSID
Push $1 ; SID struct
System::Call "*(&t${NSIS_MAX_STRLEN})p.r1"
System::Call 'advapi32::LookupAccountName(t,t,p,*i,t,*i,*i)i (n,r0,r1,${NSIS_MAX_STRLEN},n,${NSIS_MAX_STRLEN},n).r0'
${If} $0 != 0
System::Call 'advapi32::ConvertSidToStringSid(p,*t) (r1,.r0)'
${Else}
StrCpy $0 ''
${EndIf}
System::Free $1
Pop $1
Exch $0
Pop ${outSID}
${Else}
StrCpy ${outSID} ''
${EndIf}
!macroend
/* NET_DISPLAY_USER.usri1_flags flags:
UF_SCRIPT=0x0001
UF_ACCOUNTDISABLE=0x0002
UF_PASSWD_NOTREQD=0x0020
UF_NORMAL_ACCOUNT=0x0200
UF_DONT_EXPIRE_PASSWD=0x10000
UF_ACCOUNT_TYPE_MASK=UF_TEMP_DUPLICATE_ACCOUNT|UF_NORMAL_ACCOUNT|UF_INTERDOMAIN_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT
UF_DONT_REQUIRE_PREAUTH=0x400000
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED=0x0080
UF_HOMEDIR_REQUIRED=0x0008
UF_INTERDOMAIN_TRUST_ACCOUNT=0x0800
UF_LOCKOUT=0x0010
UF_MACHINE_ACCOUNT_MASK=UF_INTERDOMAIN_TRUST_ACCOUNT|UF_WORKSTATION_TRUST_ACCOUNT|UF_SERVER_TRUST_ACCOUNT
UF_MNS_LOGON_ACCOUNT=0x20000
UF_NOT_DELEGATED=0x100000
UF_NO_AUTH_DATA_REQUIRED=0x2000000
UF_PARTIAL_SECRETS_ACCOUNT=0x4000000
UF_PASSWD_CANT_CHANGE=0x0040
UF_PASSWORD_EXPIRED=0x800000
UF_SERVER_TRUST_ACCOUNT=0x2000
UF_SETTABLE_BITS=UF_SCRIPT|UF_ACCOUNTDISABLE|UF_LOCKOUT|UF_HOMEDIR_REQUIRED|UF_PASSWD_NOTREQD|UF_PASSWD_CANT_CHANGE|UF_ACCOUNT_TYPE_MASK|UF_DONT_EXPIRE_PASSWD|UF_MNS_LOGON_ACCOUNT|UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED|UF_SMARTCARD_REQUIRED|UF_TRUSTED_FOR_DELEGATION|UF_NOT_DELEGATED|UF_USE_DES_KEY_ONLY|UF_DONT_REQUIRE_PREAUTH|UF_PASSWORD_EXPIRED|UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION|UF_NO_AUTH_DATA_REQUIRED|UF_USE_AES_KEYS|
UF_SMARTCARD_REQUIRED=0x40000
UF_TEMP_DUPLICATE_ACCOUNT=0x0100
UF_TRUSTED_FOR_DELEGATION=0x80000
UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION=0x1000000
UF_USE_AES_KEYS=0x8000000
UF_USE_DES_KEY_ONLY=0x200000
UF_WORKSTATION_TRUST_ACCOUNT=0x1000
*/
!define CountUsersQ `!insertmacro CountUsersQ - `
!define PrintUsersQ `!insertmacro CountUsersQ show `
!macro CountUsersQ showinfo outVar
Push $0 ; [out] result
Push $1 ; number of struct_NET_DISPLAY_USER entries
Push $2 ; pointer to first struct_NET_DISPLAY_USER entry
Push $3 ; tmp
Push $4 ; username
Push $5 ;
Push $6 ;
Push $7 ;
Push $8 ;
Push $9 ;
Push $R0
StrCpy $0 0
StrCpy $R0 ''
System::Call "netapi32::NetQueryDisplayInformation(tn,i1,i0,i-1,i${NSIS_MAX_STRLEN},*i.r1,*i.r2)i.r3"
${If} $3 = 0
${For} $3 1 $1
System::Call "*$2(t.r4,t,i.r5,t.r6,i,i)"
${GetUserSID} $9 $4
${EnumUsersRegEx_GetProfilePath} $8 $9
!if '${showinfo}' == 'show'
DetailPrint 'SID::: $9'
IntFmt $5 0x%08X $5
StrCpy $R0 'FLAGS: $5'
IntOp $7 $5 & 0x0002 ; UF_ACCOUNTDISABLE
StrCmp $7 0 +2
StrCpy $R0 '$R0 DISABLED'
DetailPrint $R0
DetailPrint 'NAME:: $4 ($6)'
DetailPrint 'PROF:: [$8]'
DetailPrint ''
!endif
StrCmp $8 '' +2
IntOp $0 $0 + 1
IntOp $2 $2 + 24 ; move ptr to next struct in buffer
${Next}
System::Call "netapi32::NetApiBufferFree(i) (r2)"
${EndIf}
Pop $R0
Pop $9
Pop $8
Pop $7
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
Pop ${outVar}
!macroend
Section CountUsers
${PrintUsersQ} $0
SectionEnd