Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I think I saw a technique somewhere, that allows to do it from a command line (let's forget about Outlook Web for second, shall we?), but am not 100% certain ... Is it doable?

share|improve this question
    
It's definitely doable; AD protocols, both old proprietary (SAMR) and new standard (LDAP, Kerberos), are well-known. But oddly, all commands I can remember are for Linux/Unixes. –  grawity Aug 20 '12 at 12:52
add comment

2 Answers

You might try doing this with the net user-command. Try this:

net user USERNAME PASSWORD /domain YOURDOMAINNAME

or

net user USERNAME * /domain YOURDOMAINNAME

to get a prompt for the new password.

share|improve this answer
    
no such luck ... been there done that ... –  Darek Aug 20 '12 at 16:07
    
Are you sure you have access to the DC from the computer you've got in mind? Try pinging the DC by using its internal name. If not, a firewall or vlan-separation could be the cause to your lack of success. –  Simon Aronsson Aug 21 '12 at 5:25
    
That's a negative. I can use everything on the domain, even hookup my Win7 credentials to various domain accounts. –  Darek Aug 28 '12 at 15:21
    
I have found a utility that does just that. It is called passwd, written in C. Will post source shortly. –  Darek Oct 15 '13 at 17:28
add comment
up vote 0 down vote accepted

Here is the C source of a utility that does just that:

#include <windows.h>
#include <lm.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>

#define MAXNAMELEN 200
#define MAXPASSWDLEN 50

#define RETVAL_SUCCESS 0
#define RETVAL_INVALID_CMDLINE 1
#define RETVAL_BREAK 2
#define RETVAL_VERIFY_ERROR 3
#define RETVAL_CHANGE_ERROR 4

#define CH_BACKSPACE  8
#define CH_ENTER     13
#define CH_BLANK     32
#define CH_ASTERISK  42

#define AnsiToUnicode(FROM,TO)           \
    MultiByteToWideChar(CP_ACP,          \
                        0,               \
                        FROM,            \
                        strlen(FROM)+1,  \
                        TO,              \
                        sizeof(TO))

#define OemToUnicode(FROM,TO)            \
    MultiByteToWideChar(CP_OEMCP,        \
                        0,               \
                        FROM,            \
                        strlen(FROM)+1,  \
                        TO,              \
                        sizeof(TO))

UCHAR szAccountName[MAXNAMELEN];
UCHAR szDomainName[MAXNAMELEN];
UCHAR szSpecifiedAccountName[MAXNAMELEN];
UCHAR szSpecifiedDomainName[MAXNAMELEN];
UCHAR szOldPassword[MAXPASSWDLEN];
UCHAR szNewPassword[MAXPASSWDLEN];
UCHAR szVerification[MAXPASSWDLEN];

WCHAR wszAccountName[MAXNAMELEN];
WCHAR wszDomainName[MAXNAMELEN];
WCHAR wszOldPassword[MAXPASSWDLEN];
WCHAR wszNewPassword[MAXPASSWDLEN];

BOOL bQuiet=FALSE;
BOOL bInfo=FALSE;
BOOL bPasswordsSpecified=FALSE;
BOOL bUserSpecified=FALSE;
BOOL bDomainSpecified=FALSE;

void Usage(char *cmdname)
{
    printf("Usage: %s [-q] [-i] [-p oldpass newpass] [-u user] [-d domain]\n",cmdname);
    printf("       change password on the command line\n");
    printf("       -q (quiet)     suppress display of * while entering passwords\n");
    printf("       -i (info)      print account and domain information\n");
    printf("       -p (passwords) specify old and new password on the command line\n");
    printf("       -u (user)      change password for any other user (default: you)\n");
    printf("       -d (domain)    select a different domain/machine (default: your domain)\n");
    printf("       (C) 1997 by Alexander Frink (Alexander.Frink@Uni-Mainz.DE)\n");
    printf("                All rights reserved.\n");
    exit(RETVAL_INVALID_CMDLINE);
}

void ProcessCmdLine(int argc, char *argv[])
{
    char c, *p, *arg0;

    // algorithm for command line processing taken from SDK sample 
    // Win32/WinNT/Floppy/MFMT.C

    arg0=argv[0];

    if ( argc > 1 ) { 
        while (--argc > 0 ) { 
            p = *++argv; 
            if (*p == '/' || *p == '-') { 
                while (c = *++p) {
                    switch (tolower(c)) { 
                    case '?': 
                        Usage(arg0);
                        break; 
                    case 'q': 
                        bQuiet = TRUE; 
                        break; 
                    case 'i': 
                        bInfo = TRUE;
                        break;
                    case 'p': 
                        if (argc<3) Usage(arg0);
                        bPasswordsSpecified = TRUE;
                        argc--, argv++; 
                        strcpy(szOldPassword,*argv); 
                        argc--, argv++; 
                        strcpy(szNewPassword,*argv); 
                        break;
                    case 'u': 
                        if (argc<2) Usage(arg0);
                        bUserSpecified = TRUE;
                        argc--, argv++; 
                        strcpy(szSpecifiedAccountName,*argv); 
                        break;
                    case 'd': 
                        if (argc<2) Usage(arg0);
                        bDomainSpecified = TRUE;
                        argc--, argv++; 
                        strcpy(szSpecifiedDomainName,*argv); 
                        break;
                    default: 
                        Usage(arg0); 
                        break; 
                    } 
                } 
            }
        } 
    } 

}

void GetUserAndDomain(UCHAR *szAccountName, UCHAR *szDomainName)
{
    HANDLE hProcess, hAccessToken;
    UCHAR InfoBuffer[1000];
    PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;
    DWORD dwInfoBufferSize, dwAccountSize = MAXNAMELEN, dwDomainSize = MAXNAMELEN;
    SID_NAME_USE snu;

    hProcess = GetCurrentProcess();

    OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken);

    GetTokenInformation(hAccessToken,
                        TokenUser,
                        InfoBuffer,
                        1000,
                        &dwInfoBufferSize);

    LookupAccountSid(NULL,
                     pTokenUser->User.Sid,
                     szAccountName,
                     &dwAccountSize,
                     szDomainName,
                     &dwDomainSize,
                     &snu);
}

BOOL GetPassword(UCHAR *szPrompt,UCHAR *szPasswd)
{
/*
    this subroutine is partially (C) by
    Steffen Krause: skrause@informatik.hu-berlin.de,
    the author of SuSrv, a SU utility for Windows NT
    Improvements: allow correction of typing errors (with 'Backspace')
                  exit on CTRL-C (returns FALSE, otherwise TRUE)
                  skip non-printable characters (function/cursor/escape)
                  optional: suppress *'s while entering password
*/

    int i;
    int ch;
    i = 0;
    printf("%s",szPrompt);
    while(((ch = _getch()) != CH_ENTER) && (i < MAXPASSWDLEN))
    {
        if (ch==CH_BACKSPACE) {
            if (i>0) {
                szPasswd[i]=0;
                i--;
                if (!bQuiet) {
                    _putch(CH_BACKSPACE);
                    _putch(CH_BLANK);
                    _putch(CH_BACKSPACE);
                }
            }
        } else if (ch==3) {
            szPasswd[0]=0;
            return FALSE;
        } else if ((ch==0)||(ch==224)) {
            // probably function or cursor key, skip this and next character
            ch=_getch();
        } else if (ch==27) {
            // escape key, skip
        } else {
            szPasswd[i++] = ch;
            if (!bQuiet) {
                _putch(CH_ASTERISK);
            }
        }
    }
    szPasswd[i] = 0;
    return TRUE;
}

void PrintErrorMessage(NET_API_STATUS status)
{
    /*
    In contrast to the documentation on NetUserChangePassword
    (SDK 4.0 and VC++ 4.2), other error codes in addition to the listed
    NET_API_STATUS are returned. Therefore I decided to list all possible
    errors from winerror.h which have to do with passwords.
    */

    switch (status) {
    case NERR_Success:
        // nothing to do
        break;
    case ERROR_ACCESS_DENIED:
        printf("Error: The user does not have access to the requested information.\n");
        break;
    case NERR_InvalidComputer:
        printf("Error: The computer name is invalid.\n");
        break;
    case NERR_NotPrimary:
        printf("Error: The operation is allowed only on the primary domain controller of the domain.\n");
        break;
    case NERR_UserNotFound:
        printf("Error: The user name could not be found.\n");
        break;
    case NERR_PasswordTooShort:
        printf("Error: The password is shorter than required.\n");
        break;
    case ERROR_INVALID_PASSWORD:
        printf("Error: The specified network password is not correct.\n");
        break;
    case ERROR_INVALID_PASSWORDNAME:
        printf("Error: The format of the specified password is invalid.\n");
        break;
    case ERROR_NULL_LM_PASSWORD:
        printf("Error: The NT password is too complex to be converted to a LAN Manager password.\n");
        break;
    case ERROR_WRONG_PASSWORD:
        printf("Error: Unable to update the password. The value provided as the current password is incorrect.\n");
        break;
    case ERROR_ILL_FORMED_PASSWORD:
        printf("Error: Unable to update the password. The value provided for the new password contains values that are not allowed in passwords.\n");
        break;
    case ERROR_PASSWORD_RESTRICTION:
        printf("Error: Unable to update the password because a password update rule has been violated.\n");
        break;
    case ERROR_LOGON_FAILURE:
        printf("Error: Logon failure: unknown user name or bad password.\n");
        break;
    case ERROR_PASSWORD_EXPIRED:
        printf("Error: Logon failure: the specified account password has expired.\n");
        break;
    case ERROR_NT_CROSS_ENCRYPTION_REQUIRED:
        printf("Error: A cross-encrypted password is necessary to change a user password.\n");
        break;
    case ERROR_LM_CROSS_ENCRYPTION_REQUIRED:
        printf("Error: A cross-encrypted password is necessary to change this user password.\n");
        break;
    case ERROR_NO_SUCH_DOMAIN:
        printf("Error: The specified domain did not exist.\n");
        break;
    default:
        printf("Error: Undocumented error code %i.",status);
    }
}

int main(int argc, char *argv[])
{
    NET_API_STATUS status;

    ProcessCmdLine(argc, argv);

    GetUserAndDomain(szAccountName,szDomainName);
    if (bUserSpecified) {
        strcpy(szAccountName,szSpecifiedAccountName);
    }
    if (bDomainSpecified) {
        strcpy(szDomainName,szSpecifiedDomainName);
    }

    if (bInfo) {
        printf("Changing password for user '%s' on domain or machine '%s'...\n",szAccountName,szDomainName);
    }

    if (!bPasswordsSpecified) {
        if (!GetPassword("Old password: ",szOldPassword)) {
            return RETVAL_BREAK;
        }
        if (!GetPassword("\nNew password: ",szNewPassword)) {
            return RETVAL_BREAK;
        }
        if (!GetPassword("\nVerification: ",szVerification)) {
            return RETVAL_BREAK;
        }
        printf("\n");

        if (strcmp(szNewPassword,szVerification)!=0) {
            printf("Password verification failed!\n");
            return RETVAL_VERIFY_ERROR;
        }
    }

    AnsiToUnicode(szAccountName,wszAccountName);
    AnsiToUnicode(szDomainName,wszDomainName);
    OemToUnicode(szOldPassword,wszOldPassword);
    OemToUnicode(szNewPassword,wszNewPassword);

    status=NetUserChangePassword(wszDomainName,
                                 wszAccountName,
                                 wszOldPassword,
                                 wszNewPassword);
    if (status==NERR_Success) {
        return RETVAL_SUCCESS;
    } else {
        PrintErrorMessage(status);
        return RETVAL_CHANGE_ERROR;
    }
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.