I'm creating a user with the NetUserAdd API. It returns successfully, the user has a User folder and I can see the username with wmic useraccount get name. However, the created user is not visible under the control panel, nor on the logon screen. I assume that I need to add the user to some group but I don't know which or how.
Here is how I create the user:
USER_INFO_1 user_info;
ZeroMemory(&user_info, sizeof(user_info));
user_info.usri1_name = userName;
user_info.usri1_password = password;
user_info.usri1_priv = USER_PRIV_USER;
user_info.usri1_flags = UF_SCRIPT | UF_DONT_EXPIRE_PASSWD;
DWORD dwLevel = 1;
DWORD dwError = 0;
NET_API_STATUS nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&user_info, &dwError);
How can I make the user visible on the logon screen?
You have created the user but you need to add it to the users group using NetLocalGroupAddMembers.
EDIT: Just realized I was providing the method for .NET. See this example for C++.
The user was not showing up on the welcome screen because it was not added to the Users group. This is how to do it:
LOCALGROUP_MEMBERS_INFO_3 lmi3;
ZeroMemory(&lmi3, sizeof lmi3);
lmi3.lgrmi3_domainandname = user_info.usri1_name;
DWORD err = NetLocalGroupAddMembers(NULL, L"Users", 3, (LPBYTE) &lmi3, 1);
Related
I modified my username in Control Panel -> User Accounts -> Change Your Name.
But when I use the GetUserName function, it returned my old username.
How do I get the new one?
EDIT 1
Here's the code as requested:
char user[UNLEN + 1];
DWORD user_len = UNLEN + 1;
GetUserName(user, &user_len);
Try to use the API GetUserNameEx, and passing as a format NameDisplay. I guess you changed the display name of the user, not the logon name.
On Windows 7 to retrieve the name of a logged on user I can do this:
LPTSTR pUserName = NULL;
DWORD dwcbSzUserName = 0;
//'dwSessID' = user session ID
if(WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessID, WTSUserName, &pUserName, &dwcbSzUserName))
{
//Got user name in 'pUserName'
}
if(pUserName)
WTSFreeMemory(pUserName);
But on Windows 8 it returns some abbreviated name, for instance, "john_000" when the actual user's name is "John A. Doe".
So what is the way to retrieve the name of the logged on user (and possibly their email) on Windows 8 with C++ using WinAPIs as it's shown at log-on screen?
You could try NetUserGetInfo with USER_INFO_23 to get full name.
Something basically like:
//Got user name in 'pUserName'
NetUserGetInfo(NULL, pUserName, 23, my_USER_INFO_23);
//Got display name in my_USER_INFO_23.usri23_full_name
On Windows 7 to retrieve the name of a logged on user I can do this:
LPTSTR pUserName = NULL;
DWORD dwcbSzUserName = 0;
//'dwSessID' = user session ID
if(WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessID, WTSUserName, &pUserName, &dwcbSzUserName))
{
//Got user name in 'pUserName'
}
if(pUserName)
WTSFreeMemory(pUserName);
But on Windows 8 it returns some abbreviated name, for instance, "john_000" when the actual user's name is "John A. Doe".
So what is the way to retrieve the name of the logged on user (and possibly their email) on Windows 8 with C++ using WinAPIs as it's shown at log-on screen?
You could try NetUserGetInfo with USER_INFO_23 to get full name.
Something basically like:
//Got user name in 'pUserName'
NetUserGetInfo(NULL, pUserName, 23, my_USER_INFO_23);
//Got display name in my_USER_INFO_23.usri23_full_name
I'm trying to open the MessageStore of a user using MAPI. The weird thing is, when I run this a console application, while I'm logged with the user, everything works fine.
But when I run this as a Windows Service I get MAPI_E_NOT_FOUND when trying to open the MessageStore.
I already configured the service to run as the user.
MapiLogonEx seems to work fine and GetMsgStoreTables also gives me the correct results (I verfied that the EntryID of the MessageStore is correct).
Here's my code:
LPMAPITABLE pStoresTbl = NULL;
m_lpMAPISession->GetMsgStoresTable(0, &pStoresTbl);
// Query Collumns
LPSPropTagArray pTags = NULL;
LPSRowSet pRows = NULL;
pStoresTbl->SeekRow(BOOKMARK_BEGINNING,0,NULL);
pStoresTbl->QueryRows(
LONG_MAX,
NULL,
&pRows);
LPSBinary lpEntryID = NULL;
ULONG iprops;
for (iprops = 0; iprops < pRows->aRow[0].cValues; iprops++)
{
SPropValue sProp = pRows->aRow[0].lpProps[iprops];
if (PROP_ID(sProp.ulPropTag) == PROP_ID(PR_ENTRYID))
{
lpEntryID = &sProp.Value.bin;
break;
}
}
lpMDB = NULL;
HRESULT hres = m_lpMAPISession->OpenMsgStore(NULL,
lpEntryID->cb,
(LPENTRYID) lpEntryID->lpb,
NULL,
MDB_NO_DIALOG |
MDB_NO_MAIL | // spooler not notified of our presence
MDB_TEMPORARY | // message store not added to MAPI profile
MAPI_BEST_ACCESS,
&lpMDB);
Is that an Exchange profile? Are you sure you are opening the primary mailbox rather than the PF store?
Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
Do you pass in the MAPI_NT_SERVICE flag in the MAPIINIT_0 structure when calling MAPIInitialize? I've never not passed it in when running in a service, so I'm not exactly sure what happens if you don't. The MSDN docs say it is required.
MAPI_NT_SERVICE
The caller is
running as a Windows service. Callers
that are not running as a Windows
service should not set this flag;
callers that are running as a service
must set this flag.
I want to get the process's user name and check if it is a local administrator . Or check directly if the current procees user is a local administrator
Get the current username with GetUserName(), then call NetUserGetInfo() with the server name (NULL for local) and username you just got. Pass it a USER_INFO_1 structure, and then access usri1_priv in the structure. If the value is USER_PRIV_ADMIN, then you'll know that the username is an admin.
Tested on Windows XP SP3, Windows 7 32 bit and 64 bit with admin user and non-admin user.
Code ported from equivalent C# and uses ATL windows security wrapper classes.
#include <atlbase.h>
#include <atlsecurity.h>
// The function returns true if the user who is running the
// application is a member of the Administrators group,
// which does not necessarily mean the process has admin privileges.
bool IsAdministrator(HRESULT &rHr)
{
bool bIsAdmin = false;
try
{
// Open the access token of the current process.
ATL::CAccessToken aToken;
if (!aToken.GetProcessToken(TOKEN_QUERY))
{
throw MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32,
::GetLastError());
}
// Query for the access token's group information.
ATL::CTokenGroups groups;
if (!aToken.GetGroups(&groups))
{
throw MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32,
::GetLastError());
}
// Iterate through the access token's groups
// looking for a match against the builtin admins group.
ATL::CSid::CSidArray groupSids;
ATL::CAtlArray<DWORD> groupAttribs;
groups.GetSidsAndAttributes(&groupSids, &groupAttribs);
for (UINT i = 0; !bIsAdmin && i < groupSids.GetCount(); ++i)
{
bIsAdmin = groupSids.GetAt(i) == ATL::Sids::Admins();
}
rHr = S_OK;
}
catch (HRESULT hr)
{
rHr = hr;
}
return bIsAdmin;
}
Presuming you're on a Window OS there's a shell function: IsUserAnAdmin
See MSDN article
This article does suggest rolling your own function though, use CheckTokenMembership. There is even a code example to help you along.