diff options
Diffstat (limited to 'src')
29 files changed, 900 insertions, 180 deletions
diff --git a/src/ext/Iis/ca/sca.h b/src/ext/Iis/ca/sca.h index 64567dcb..6921613b 100644 --- a/src/ext/Iis/ca/sca.h +++ b/src/ext/Iis/ca/sca.h | |||
| @@ -121,4 +121,5 @@ enum SCAU_ATTRIBUTES | |||
| 121 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, | 121 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, |
| 122 | SCAU_DONT_CREATE_USER = 0x00000200, | 122 | SCAU_DONT_CREATE_USER = 0x00000200, |
| 123 | SCAU_NON_VITAL = 0x00000400, | 123 | SCAU_NON_VITAL = 0x00000400, |
| 124 | SCAU_REMOVE_COMMENT = 0x00000800, | ||
| 124 | }; | 125 | }; |
diff --git a/src/ext/Util/ca/sca.h b/src/ext/Util/ca/sca.h index 599122ff..84f5ffd9 100644 --- a/src/ext/Util/ca/sca.h +++ b/src/ext/Util/ca/sca.h | |||
| @@ -16,4 +16,5 @@ enum SCAU_ATTRIBUTES | |||
| 16 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, | 16 | SCAU_DONT_REMOVE_ON_UNINSTALL = 0x00000100, |
| 17 | SCAU_DONT_CREATE_USER = 0x00000200, | 17 | SCAU_DONT_CREATE_USER = 0x00000200, |
| 18 | SCAU_NON_VITAL = 0x00000400, | 18 | SCAU_NON_VITAL = 0x00000400, |
| 19 | }; \ No newline at end of file | 19 | SCAU_REMOVE_COMMENT = 0x00000800, |
| 20 | }; | ||
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp index 5845c1b4..7bd271d1 100644 --- a/src/ext/Util/ca/scaexec.cpp +++ b/src/ext/Util/ca/scaexec.cpp | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | 2 | ||
| 3 | #include "precomp.h" | 3 | #include "precomp.h" |
| 4 | 4 | ||
| 5 | |||
| 6 | /******************************************************************** | 5 | /******************************************************************** |
| 7 | * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares | 6 | * CreateSmb - CUSTOM ACTION ENTRY POINT for creating fileshares |
| 8 | * | 7 | * |
| @@ -520,55 +519,88 @@ static HRESULT ModifyUserLocalBatchRight( | |||
| 520 | return hr; | 519 | return hr; |
| 521 | } | 520 | } |
| 522 | 521 | ||
| 523 | static void SetUserPasswordAndAttributes( | 522 | static HRESULT ApplyAttributes(int iAttributes, DWORD* pFlags) |
| 524 | __in USER_INFO_1* puserInfo, | ||
| 525 | __in LPWSTR wzPassword, | ||
| 526 | __in int iAttributes | ||
| 527 | ) | ||
| 528 | { | 523 | { |
| 529 | Assert(puserInfo); | 524 | HRESULT hr = S_OK; |
| 530 | |||
| 531 | // Set the User's password | ||
| 532 | puserInfo->usri1_password = wzPassword; | ||
| 533 | 525 | ||
| 534 | // Apply the Attributes | ||
| 535 | if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) | 526 | if (SCAU_DONT_EXPIRE_PASSWRD & iAttributes) |
| 536 | { | 527 | { |
| 537 | puserInfo->usri1_flags |= UF_DONT_EXPIRE_PASSWD; | 528 | *pFlags |= UF_DONT_EXPIRE_PASSWD; |
| 538 | } | 529 | } |
| 539 | else | 530 | else |
| 540 | { | 531 | { |
| 541 | puserInfo->usri1_flags &= ~UF_DONT_EXPIRE_PASSWD; | 532 | *pFlags &= ~UF_DONT_EXPIRE_PASSWD; |
| 542 | } | 533 | } |
| 543 | 534 | ||
| 544 | if (SCAU_PASSWD_CANT_CHANGE & iAttributes) | 535 | if (SCAU_PASSWD_CANT_CHANGE & iAttributes) |
| 545 | { | 536 | { |
| 546 | puserInfo->usri1_flags |= UF_PASSWD_CANT_CHANGE; | 537 | *pFlags |= UF_PASSWD_CANT_CHANGE; |
| 547 | } | 538 | } |
| 548 | else | 539 | else |
| 549 | { | 540 | { |
| 550 | puserInfo->usri1_flags &= ~UF_PASSWD_CANT_CHANGE; | 541 | *pFlags &= ~UF_PASSWD_CANT_CHANGE; |
| 551 | } | 542 | } |
| 552 | 543 | ||
| 553 | if (SCAU_DISABLE_ACCOUNT & iAttributes) | 544 | if (SCAU_DISABLE_ACCOUNT & iAttributes) |
| 554 | { | 545 | { |
| 555 | puserInfo->usri1_flags |= UF_ACCOUNTDISABLE; | 546 | *pFlags |= UF_ACCOUNTDISABLE; |
| 556 | } | 547 | } |
| 557 | else | 548 | else |
| 558 | { | 549 | { |
| 559 | puserInfo->usri1_flags &= ~UF_ACCOUNTDISABLE; | 550 | *pFlags &= ~UF_ACCOUNTDISABLE; |
| 560 | } | 551 | } |
| 561 | 552 | ||
| 562 | if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work | 553 | if (SCAU_PASSWD_CHANGE_REQD_ON_LOGIN & iAttributes) // TODO: for some reason this doesn't work |
| 563 | { | 554 | { |
| 564 | puserInfo->usri1_flags |= UF_PASSWORD_EXPIRED; | 555 | *pFlags |= UF_PASSWORD_EXPIRED; |
| 565 | } | 556 | } |
| 566 | else | 557 | else |
| 567 | { | 558 | { |
| 568 | puserInfo->usri1_flags &= ~UF_PASSWORD_EXPIRED; | 559 | *pFlags &= ~UF_PASSWORD_EXPIRED; |
| 560 | } | ||
| 561 | |||
| 562 | return hr; | ||
| 563 | } | ||
| 564 | |||
| 565 | static HRESULT ApplyComment(int iAttributes, LPWSTR pwzComment, LPWSTR* ppComment) | ||
| 566 | { | ||
| 567 | HRESULT hr = S_OK; | ||
| 568 | |||
| 569 | if (SCAU_REMOVE_COMMENT & iAttributes) | ||
| 570 | { | ||
| 571 | *ppComment = L""; | ||
| 572 | } | ||
| 573 | else if (pwzComment && *pwzComment) | ||
| 574 | { | ||
| 575 | *ppComment = pwzComment; | ||
| 569 | } | 576 | } |
| 577 | |||
| 578 | return hr; | ||
| 579 | } | ||
| 580 | |||
| 581 | static NET_API_STATUS SetUserPassword(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzPassword) | ||
| 582 | { | ||
| 583 | _USER_INFO_1003 userInfo1003; | ||
| 584 | |||
| 585 | userInfo1003.usri1003_password = pwzPassword; | ||
| 586 | return ::NetUserSetInfo(pwzServerName, pwzName, 1003, reinterpret_cast<LPBYTE>(&userInfo1003), NULL); | ||
| 570 | } | 587 | } |
| 571 | 588 | ||
| 589 | static NET_API_STATUS SetUserComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzComment) | ||
| 590 | { | ||
| 591 | _USER_INFO_1007 userInfo1007; | ||
| 592 | |||
| 593 | userInfo1007.usri1007_comment = pwzComment; | ||
| 594 | return ::NetUserSetInfo(pwzServerName, pwzName, 1007, reinterpret_cast<LPBYTE>(&userInfo1007), NULL); | ||
| 595 | } | ||
| 596 | |||
| 597 | static NET_API_STATUS SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) | ||
| 598 | { | ||
| 599 | _USER_INFO_1008 userInfo1008; | ||
| 600 | |||
| 601 | userInfo1008.usri1008_flags = flags; | ||
| 602 | return ::NetUserSetInfo(pwzServerName, pwzName, 1008, reinterpret_cast<LPBYTE>(&userInfo1008), NULL); | ||
| 603 | } | ||
| 572 | 604 | ||
| 573 | static HRESULT RemoveUserInternal( | 605 | static HRESULT RemoveUserInternal( |
| 574 | LPWSTR wzGroupCaData, | 606 | LPWSTR wzGroupCaData, |
| @@ -624,7 +656,12 @@ static HRESULT RemoveUserInternal( | |||
| 624 | } | 656 | } |
| 625 | if (ERROR_SUCCESS == er) | 657 | if (ERROR_SUCCESS == er) |
| 626 | { | 658 | { |
| 627 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 659 | if (2 <= wcslen(pDomainControllerInfo->DomainControllerName)) |
| 660 | { | ||
| 661 | wz = pDomainControllerInfo->DomainControllerName + 2; // Add 2 so that we don't get the \\ prefix. | ||
| 662 | // Pass the entire string if it is too short | ||
| 663 | // to have a \\ prefix. | ||
| 664 | } | ||
| 628 | } | 665 | } |
| 629 | else | 666 | else |
| 630 | { | 667 | { |
| @@ -680,6 +717,41 @@ LExit: | |||
| 680 | return hr; | 717 | return hr; |
| 681 | } | 718 | } |
| 682 | 719 | ||
| 720 | static HRESULT GetServerName(LPWSTR pwzDomain, LPWSTR* ppwzServerName) | ||
| 721 | { | ||
| 722 | HRESULT hr = S_OK; | ||
| 723 | |||
| 724 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 725 | UINT er; | ||
| 726 | |||
| 727 | if (pwzDomain && *pwzDomain) | ||
| 728 | { | ||
| 729 | er = ::DsGetDcNameW(NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo); | ||
| 730 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
| 731 | { | ||
| 732 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 733 | er = ::DsGetDcNameW(NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo); | ||
| 734 | } | ||
| 735 | if (ERROR_SUCCESS == er | ||
| 736 | && 2 <= wcslen(pDomainControllerInfo->DomainControllerName) | ||
| 737 | && '\\' == *pDomainControllerInfo->DomainControllerName | ||
| 738 | && '\\' == *pDomainControllerInfo->DomainControllerName + 1) | ||
| 739 | { | ||
| 740 | *ppwzServerName = pDomainControllerInfo->DomainControllerName + 2; // Skip the \\ prefix | ||
| 741 | } | ||
| 742 | else | ||
| 743 | { | ||
| 744 | *ppwzServerName = pwzDomain; | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | if (pDomainControllerInfo) | ||
| 749 | { | ||
| 750 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
| 751 | } | ||
| 752 | |||
| 753 | return hr; | ||
| 754 | } | ||
| 683 | 755 | ||
| 684 | /******************************************************************** | 756 | /******************************************************************** |
| 685 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users | 757 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users |
| @@ -688,7 +760,7 @@ LExit: | |||
| 688 | * *****************************************************************/ | 760 | * *****************************************************************/ |
| 689 | extern "C" UINT __stdcall CreateUser( | 761 | extern "C" UINT __stdcall CreateUser( |
| 690 | __in MSIHANDLE hInstall | 762 | __in MSIHANDLE hInstall |
| 691 | ) | 763 | ) |
| 692 | { | 764 | { |
| 693 | //AssertSz(0, "Debug CreateUser"); | 765 | //AssertSz(0, "Debug CreateUser"); |
| 694 | 766 | ||
| @@ -699,11 +771,11 @@ extern "C" UINT __stdcall CreateUser( | |||
| 699 | LPWSTR pwz = NULL; | 771 | LPWSTR pwz = NULL; |
| 700 | LPWSTR pwzName = NULL; | 772 | LPWSTR pwzName = NULL; |
| 701 | LPWSTR pwzDomain = NULL; | 773 | LPWSTR pwzDomain = NULL; |
| 774 | LPWSTR pwzComment = NULL; | ||
| 702 | LPWSTR pwzScriptKey = NULL; | 775 | LPWSTR pwzScriptKey = NULL; |
| 703 | LPWSTR pwzPassword = NULL; | 776 | LPWSTR pwzPassword = NULL; |
| 704 | LPWSTR pwzGroup = NULL; | 777 | LPWSTR pwzGroup = NULL; |
| 705 | LPWSTR pwzGroupDomain = NULL; | 778 | LPWSTR pwzGroupDomain = NULL; |
| 706 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 707 | int iAttributes = 0; | 779 | int iAttributes = 0; |
| 708 | BOOL fInitializedCom = FALSE; | 780 | BOOL fInitializedCom = FALSE; |
| 709 | 781 | ||
| @@ -711,10 +783,10 @@ extern "C" UINT __stdcall CreateUser( | |||
| 711 | int iOriginalAttributes = 0; | 783 | int iOriginalAttributes = 0; |
| 712 | int iRollbackAttributes = 0; | 784 | int iRollbackAttributes = 0; |
| 713 | 785 | ||
| 714 | USER_INFO_1 userInfo; | 786 | USER_INFO_1 userInfo1; |
| 715 | USER_INFO_1* puserInfo = NULL; | 787 | USER_INFO_1* pUserInfo1 = NULL; |
| 716 | DWORD dw; | 788 | DWORD dw; |
| 717 | LPCWSTR wz = NULL; | 789 | LPWSTR pwzServerName = NULL; |
| 718 | 790 | ||
| 719 | hr = WcaInitialize(hInstall, "CreateUser"); | 791 | hr = WcaInitialize(hInstall, "CreateUser"); |
| 720 | ExitOnFailure(hr, "failed to initialize"); | 792 | ExitOnFailure(hr, "failed to initialize"); |
| @@ -723,7 +795,7 @@ extern "C" UINT __stdcall CreateUser( | |||
| 723 | ExitOnFailure(hr, "failed to initialize COM"); | 795 | ExitOnFailure(hr, "failed to initialize COM"); |
| 724 | fInitializedCom = TRUE; | 796 | fInitializedCom = TRUE; |
| 725 | 797 | ||
| 726 | hr = WcaGetProperty( L"CustomActionData", &pwzData); | 798 | hr = WcaGetProperty(L"CustomActionData", &pwzData); |
| 727 | ExitOnFailure(hr, "failed to get CustomActionData"); | 799 | ExitOnFailure(hr, "failed to get CustomActionData"); |
| 728 | 800 | ||
| 729 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | 801 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); |
| @@ -738,6 +810,9 @@ extern "C" UINT __stdcall CreateUser( | |||
| 738 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 810 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 739 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 811 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 740 | 812 | ||
| 813 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 814 | ExitOnFailure(hr, "failed to read user comment from custom action data"); | ||
| 815 | |||
| 741 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 816 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 742 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 817 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 743 | 818 | ||
| @@ -747,96 +822,155 @@ extern "C" UINT __stdcall CreateUser( | |||
| 747 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); | 822 | hr = WcaReadStringFromCaData(&pwz, &pwzPassword); |
| 748 | ExitOnFailure(hr, "failed to read password from custom action data"); | 823 | ExitOnFailure(hr, "failed to read password from custom action data"); |
| 749 | 824 | ||
| 750 | // There is no rollback scheduled if the key is empty. | ||
| 751 | // Best effort to get original configuration and save it in the script so rollback can restore it. | ||
| 752 | if (*pwzScriptKey) | ||
| 753 | { | ||
| 754 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
| 755 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
| 756 | |||
| 757 | iRollbackAttributes = 0; | ||
| 758 | hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); | ||
| 759 | if (FAILED(hr)) | ||
| 760 | { | ||
| 761 | WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); | ||
| 762 | } | ||
| 763 | else | ||
| 764 | { | ||
| 765 | if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) | ||
| 766 | { | ||
| 767 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; | ||
| 768 | } | ||
| 769 | if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) | ||
| 770 | { | ||
| 771 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; | ||
| 772 | } | ||
| 773 | } | ||
| 774 | |||
| 775 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
| 776 | ExitOnFailure(hr, "Failed to add data to rollback script."); | ||
| 777 | |||
| 778 | // Nudge the system to get all our rollback data written to disk. | ||
| 779 | WcaCaScriptFlush(hRollbackScript); | ||
| 780 | } | ||
| 781 | |||
| 782 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) | 825 | if (!(SCAU_DONT_CREATE_USER & iAttributes)) |
| 783 | { | 826 | { |
| 784 | ::ZeroMemory(&userInfo, sizeof(USER_INFO_1)); | 827 | pUserInfo1 = &userInfo1; |
| 785 | userInfo.usri1_name = pwzName; | 828 | ::ZeroMemory(pUserInfo1, sizeof(USER_INFO_1)); |
| 786 | userInfo.usri1_priv = USER_PRIV_USER; | 829 | pUserInfo1->usri1_name = pwzName; |
| 787 | userInfo.usri1_flags = UF_SCRIPT; | 830 | pUserInfo1->usri1_priv = USER_PRIV_USER; |
| 788 | userInfo.usri1_home_dir = NULL; | 831 | pUserInfo1->usri1_flags = UF_SCRIPT; |
| 789 | userInfo.usri1_comment = NULL; | 832 | pUserInfo1->usri1_home_dir = NULL; |
| 790 | userInfo.usri1_script_path = NULL; | 833 | pUserInfo1->usri1_comment = NULL; |
| 791 | 834 | pUserInfo1->usri1_script_path = NULL; | |
| 792 | SetUserPasswordAndAttributes(&userInfo, pwzPassword, iAttributes); | 835 | |
| 836 | // Set the user's password | ||
| 837 | pUserInfo1->usri1_password = pwzPassword; | ||
| 838 | |||
| 839 | // Set the user's comment | ||
| 840 | hr = ApplyComment(iAttributes, pwzComment, &pUserInfo1->usri1_comment); | ||
| 841 | ExitOnFailure(hr, "failed to apply comment"); | ||
| 842 | |||
| 843 | // Set the user's flags | ||
| 844 | hr = ApplyAttributes(iAttributes, &pUserInfo1->usri1_flags); | ||
| 845 | ExitOnFailure(hr, "failed to apply attributes"); | ||
| 793 | 846 | ||
| 794 | // | 847 | // |
| 795 | // Create the User | 848 | // Create the User |
| 796 | // | 849 | // |
| 797 | if (pwzDomain && *pwzDomain) | 850 | hr = GetServerName(pwzDomain, &pwzServerName); |
| 851 | ExitOnFailure(hr, "failed to get server name"); | ||
| 852 | |||
| 853 | er = ::NetUserAdd(pwzServerName, 1, reinterpret_cast<LPBYTE>(pUserInfo1), &dw); | ||
| 854 | if (NERR_UserExists == er) | ||
| 798 | { | 855 | { |
| 799 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, NULL, &pDomainControllerInfo ); | 856 | er = ERROR_SUCCESS; // Make sure that we don't report this situation as an error |
| 800 | if (RPC_S_SERVER_UNAVAILABLE == er) | 857 | // if we fall through the tests that follow. |
| 801 | { | 858 | if (SCAU_FAIL_IF_EXISTS & iAttributes) |
| 802 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 803 | er = ::DsGetDcNameW( NULL, (LPCWSTR)pwzDomain, NULL, NULL, DS_FORCE_REDISCOVERY, &pDomainControllerInfo ); | ||
| 804 | } | ||
| 805 | if (ERROR_SUCCESS == er) | ||
| 806 | { | 859 | { |
| 807 | wz = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 860 | hr = HRESULT_FROM_WIN32(er); |
| 861 | ExitOnFailure(hr, "User was not supposed to exist, but does."); | ||
| 808 | } | 862 | } |
| 809 | else | ||
| 810 | { | ||
| 811 | wz = pwzDomain; | ||
| 812 | } | ||
| 813 | } | ||
| 814 | 863 | ||
| 815 | er = ::NetUserAdd(wz, 1, reinterpret_cast<LPBYTE>(&userInfo), &dw); | ||
| 816 | if (NERR_UserExists == er) | ||
| 817 | { | ||
| 818 | if (SCAU_UPDATE_IF_EXISTS & iAttributes) | 864 | if (SCAU_UPDATE_IF_EXISTS & iAttributes) |
| 819 | { | 865 | { |
| 820 | er = ::NetUserGetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE*>(&puserInfo)); | 866 | pUserInfo1 = NULL; |
| 821 | if (NERR_Success == er) | 867 | er = ::NetUserGetInfo(pwzServerName, pwzName, 1, reinterpret_cast<LPBYTE*>(&pUserInfo1)); |
| 868 | if (ERROR_SUCCESS == er) | ||
| 822 | { | 869 | { |
| 823 | // Change the existing user's password and attributes again then try | 870 | // There is no rollback scheduled if the key is empty. |
| 824 | // to update user with this new data | 871 | // Best effort to get original configuration and save it in the script so rollback can restore it. |
| 825 | SetUserPasswordAndAttributes(puserInfo, pwzPassword, iAttributes); | 872 | |
| 873 | if (*pwzScriptKey) | ||
| 874 | { | ||
| 875 | // Try to open the rollback script | ||
| 876 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
| 877 | |||
| 878 | if (INVALID_HANDLE_VALUE != hRollbackScript) | ||
| 879 | { | ||
| 880 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 881 | } | ||
| 882 | else | ||
| 883 | { | ||
| 884 | hRollbackScript = NULL; | ||
| 885 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
| 886 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
| 887 | |||
| 888 | iRollbackAttributes = 0; | ||
| 889 | hr = GetExistingUserRightsAssignments(pwzDomain, pwzName, &iOriginalAttributes); | ||
| 890 | if (FAILED(hr)) | ||
| 891 | { | ||
| 892 | WcaLogError(hr, "failed to get existing user rights: %ls, continuing anyway.", pwzName); | ||
| 893 | } | ||
| 894 | else | ||
| 895 | { | ||
| 896 | if (!(SCAU_ALLOW_LOGON_AS_SERVICE & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes)) | ||
| 897 | { | ||
| 898 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_SERVICE; | ||
| 899 | } | ||
| 900 | |||
| 901 | if (!(SCAU_ALLOW_LOGON_AS_BATCH & iOriginalAttributes) && (SCAU_ALLOW_LOGON_AS_BATCH & iAttributes)) | ||
| 902 | { | ||
| 903 | iRollbackAttributes |= SCAU_ALLOW_LOGON_AS_BATCH; | ||
| 904 | } | ||
| 905 | } | ||
| 906 | |||
| 907 | hr = WcaCaScriptWriteString(hRollbackScript, pUserInfo1->usri1_comment); | ||
| 908 | ExitOnFailure(hr, "Failed to add rollback comment to rollback script."); | ||
| 909 | |||
| 910 | if (!pUserInfo1->usri1_comment || !*pUserInfo1->usri1_comment) | ||
| 911 | { | ||
| 912 | iRollbackAttributes |= SCAU_REMOVE_COMMENT; | ||
| 913 | } | ||
| 914 | |||
| 915 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
| 916 | ExitOnFailure(hr, "Failed to add rollback attributes to rollback script."); | ||
| 917 | |||
| 918 | // Nudge the system to get all our rollback data written to disk. | ||
| 919 | WcaCaScriptFlush(hRollbackScript); | ||
| 920 | } | ||
| 921 | } | ||
| 922 | } | ||
| 826 | 923 | ||
| 827 | er = ::NetUserSetInfo(wz, pwzName, 1, reinterpret_cast<LPBYTE>(puserInfo), &dw); | 924 | if (ERROR_SUCCESS == er) |
| 925 | { | ||
| 926 | hr = HRESULT_FROM_WIN32(::SetUserPassword(pwzServerName, pwzName, pwzPassword)); | ||
| 927 | if (FAILED(hr)) | ||
| 928 | { | ||
| 929 | WcaLogError(hr, "failed to set user password for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 930 | } | ||
| 931 | |||
| 932 | if (SCAU_REMOVE_COMMENT & iAttributes) | ||
| 933 | { | ||
| 934 | hr = HRESULT_FROM_WIN32(SetUserComment(pwzServerName, pwzName, L"")); | ||
| 935 | if (FAILED(hr)) | ||
| 936 | { | ||
| 937 | WcaLogError(hr, "failed to clear user comment for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 938 | } | ||
| 939 | } | ||
| 940 | else if (pwzComment && *pwzComment) | ||
| 941 | { | ||
| 942 | hr = HRESULT_FROM_WIN32(SetUserComment(pwzServerName, pwzName, pwzComment)); | ||
| 943 | if (FAILED(hr)) | ||
| 944 | { | ||
| 945 | WcaLogError(hr, "failed to set user comment to %ls for user %ls\\%ls, continuing anyway.", pwzComment, pwzServerName, pwzName); | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | DWORD flags = pUserInfo1->usri1_flags; | ||
| 950 | |||
| 951 | hr = ApplyAttributes(iAttributes, &flags); | ||
| 952 | if (FAILED(hr)) | ||
| 953 | { | ||
| 954 | WcaLogError(hr, "failed to apply attributes for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 955 | } | ||
| 956 | |||
| 957 | hr = HRESULT_FROM_WIN32(SetUserFlags(pwzServerName, pwzName, flags)); | ||
| 958 | if (FAILED(hr)) | ||
| 959 | { | ||
| 960 | WcaLogError(hr, "failed to set user flags for user %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 961 | } | ||
| 828 | } | 962 | } |
| 829 | } | 963 | } |
| 830 | else if (!(SCAU_FAIL_IF_EXISTS & iAttributes)) | ||
| 831 | { | ||
| 832 | er = NERR_Success; | ||
| 833 | } | ||
| 834 | } | 964 | } |
| 835 | else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) | 965 | else if (NERR_PasswordTooShort == er || NERR_PasswordTooLong == er) |
| 836 | { | 966 | { |
| 837 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); | 967 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreatePswd, "failed to create user: %ls due to invalid password.", pwzName); |
| 838 | } | 968 | } |
| 839 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); | 969 | |
| 970 | if (ERROR_SUCCESS != er) | ||
| 971 | { | ||
| 972 | MessageExitOnFailure(hr = HRESULT_FROM_WIN32(er), msierrUSRFailedUserCreate, "failed to create user: %ls", pwzName); | ||
| 973 | } | ||
| 840 | } | 974 | } |
| 841 | 975 | ||
| 842 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) | 976 | if (SCAU_ALLOW_LOGON_AS_SERVICE & iAttributes) |
| @@ -851,14 +985,15 @@ extern "C" UINT __stdcall CreateUser( | |||
| 851 | MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); | 985 | MessageExitOnFailure(hr, msierrUSRFailedGrantLogonAsService, "Failed to grant logon as batch job rights to user: %ls", pwzName); |
| 852 | } | 986 | } |
| 853 | 987 | ||
| 854 | // | 988 | // |
| 855 | // Add the users to groups | 989 | // Add the users to groups |
| 856 | // | 990 | // |
| 857 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | 991 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) |
| 858 | { | 992 | { |
| 859 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | 993 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); |
| 860 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); | 994 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); |
| 861 | 995 | ||
| 996 | WcaLog(LOGMSG_STANDARD, "Adding user %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup); | ||
| 862 | hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); | 997 | hr = AddUserToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); |
| 863 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); | 998 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add user: %ls to group %ls", pwzName, pwzGroup); |
| 864 | } | 999 | } |
| @@ -866,24 +1001,23 @@ extern "C" UINT __stdcall CreateUser( | |||
| 866 | { | 1001 | { |
| 867 | hr = S_OK; | 1002 | hr = S_OK; |
| 868 | } | 1003 | } |
| 1004 | |||
| 869 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); | 1005 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); |
| 870 | 1006 | ||
| 1007 | ExitOnFailure(hr, "failed to get next group in which to include user:%ls", pwzName); | ||
| 1008 | |||
| 871 | LExit: | 1009 | LExit: |
| 872 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | 1010 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); |
| 873 | 1011 | ||
| 874 | if (puserInfo) | 1012 | if (pUserInfo1 && pUserInfo1 != &userInfo1) |
| 875 | { | 1013 | { |
| 876 | ::NetApiBufferFree((LPVOID)puserInfo); | 1014 | ::NetApiBufferFree((LPVOID)pUserInfo1); |
| 877 | } | ||
| 878 | |||
| 879 | if (pDomainControllerInfo) | ||
| 880 | { | ||
| 881 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
| 882 | } | 1015 | } |
| 883 | 1016 | ||
| 884 | ReleaseStr(pwzData); | 1017 | ReleaseStr(pwzData); |
| 885 | ReleaseStr(pwzName); | 1018 | ReleaseStr(pwzName); |
| 886 | ReleaseStr(pwzDomain); | 1019 | ReleaseStr(pwzDomain); |
| 1020 | ReleaseStr(pwzComment); | ||
| 887 | ReleaseStr(pwzScriptKey); | 1021 | ReleaseStr(pwzScriptKey); |
| 888 | ReleaseStr(pwzPassword); | 1022 | ReleaseStr(pwzPassword); |
| 889 | ReleaseStr(pwzGroup); | 1023 | ReleaseStr(pwzGroup); |
| @@ -922,15 +1056,17 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 922 | 1056 | ||
| 923 | LPWSTR pwzData = NULL; | 1057 | LPWSTR pwzData = NULL; |
| 924 | LPWSTR pwz = NULL; | 1058 | LPWSTR pwz = NULL; |
| 1059 | LPWSTR pwzScriptKey = NULL; | ||
| 925 | LPWSTR pwzName = NULL; | 1060 | LPWSTR pwzName = NULL; |
| 926 | LPWSTR pwzDomain = NULL; | 1061 | LPWSTR pwzDomain = NULL; |
| 927 | LPWSTR pwzScriptKey = NULL; | 1062 | LPWSTR pwzComment = NULL; |
| 928 | int iAttributes = 0; | 1063 | int iAttributes = 0; |
| 929 | BOOL fInitializedCom = FALSE; | 1064 | BOOL fInitializedCom = FALSE; |
| 930 | 1065 | ||
| 931 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | 1066 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; |
| 932 | LPWSTR pwzRollbackData = NULL; | 1067 | LPWSTR pwzRollbackData = NULL; |
| 933 | int iOriginalAttributes = 0; | 1068 | int iOriginalAttributes = 0; |
| 1069 | LPWSTR pwzOriginalComment = NULL; | ||
| 934 | 1070 | ||
| 935 | hr = WcaInitialize(hInstall, "CreateUserRollback"); | 1071 | hr = WcaInitialize(hInstall, "CreateUserRollback"); |
| 936 | ExitOnFailure(hr, "failed to initialize"); | 1072 | ExitOnFailure(hr, "failed to initialize"); |
| @@ -957,6 +1093,9 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 957 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 1093 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 958 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 1094 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 959 | 1095 | ||
| 1096 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1097 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1098 | |||
| 960 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 1099 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 961 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 1100 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 962 | 1101 | ||
| @@ -978,6 +1117,15 @@ extern "C" UINT __stdcall CreateUserRollback( | |||
| 978 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); | 1117 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); |
| 979 | 1118 | ||
| 980 | pwz = pwzRollbackData; | 1119 | pwz = pwzRollbackData; |
| 1120 | hr = WcaReadStringFromCaData(&pwz, &pwzOriginalComment); | ||
| 1121 | if (FAILED(hr)) | ||
| 1122 | { | ||
| 1123 | WcaLogError(hr, "failed to read comment from rollback data, continuing anyway"); | ||
| 1124 | } | ||
| 1125 | else | ||
| 1126 | { | ||
| 1127 | pwzComment = pwzOriginalComment; | ||
| 1128 | } | ||
| 981 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); | 1129 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); |
| 982 | if (FAILED(hr)) | 1130 | if (FAILED(hr)) |
| 983 | { | 1131 | { |
| @@ -998,8 +1146,10 @@ LExit: | |||
| 998 | ReleaseStr(pwzData); | 1146 | ReleaseStr(pwzData); |
| 999 | ReleaseStr(pwzName); | 1147 | ReleaseStr(pwzName); |
| 1000 | ReleaseStr(pwzDomain); | 1148 | ReleaseStr(pwzDomain); |
| 1149 | ReleaseStr(pwzComment); | ||
| 1001 | ReleaseStr(pwzScriptKey); | 1150 | ReleaseStr(pwzScriptKey); |
| 1002 | ReleaseStr(pwzRollbackData); | 1151 | ReleaseStr(pwzRollbackData); |
| 1152 | ReleaseStr(pwzOriginalComment); | ||
| 1003 | 1153 | ||
| 1004 | if (fInitializedCom) | 1154 | if (fInitializedCom) |
| 1005 | { | 1155 | { |
| @@ -1033,6 +1183,7 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 1033 | LPWSTR pwz = NULL; | 1183 | LPWSTR pwz = NULL; |
| 1034 | LPWSTR pwzName = NULL; | 1184 | LPWSTR pwzName = NULL; |
| 1035 | LPWSTR pwzDomain = NULL; | 1185 | LPWSTR pwzDomain = NULL; |
| 1186 | LPWSTR pwzComment = NULL; | ||
| 1036 | int iAttributes = 0; | 1187 | int iAttributes = 0; |
| 1037 | BOOL fInitializedCom = FALSE; | 1188 | BOOL fInitializedCom = FALSE; |
| 1038 | 1189 | ||
| @@ -1058,6 +1209,9 @@ extern "C" UINT __stdcall RemoveUser( | |||
| 1058 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | 1209 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); |
| 1059 | ExitOnFailure(hr, "failed to read domain from custom action data"); | 1210 | ExitOnFailure(hr, "failed to read domain from custom action data"); |
| 1060 | 1211 | ||
| 1212 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1213 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1214 | |||
| 1061 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | 1215 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); |
| 1062 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | 1216 | ExitOnFailure(hr, "failed to read attributes from custom action data"); |
| 1063 | 1217 | ||
| @@ -1067,6 +1221,7 @@ LExit: | |||
| 1067 | ReleaseStr(pwzData); | 1221 | ReleaseStr(pwzData); |
| 1068 | ReleaseStr(pwzName); | 1222 | ReleaseStr(pwzName); |
| 1069 | ReleaseStr(pwzDomain); | 1223 | ReleaseStr(pwzDomain); |
| 1224 | ReleaseStr(pwzComment); | ||
| 1070 | 1225 | ||
| 1071 | if (fInitializedCom) | 1226 | if (fInitializedCom) |
| 1072 | { | 1227 | { |
diff --git a/src/ext/Util/ca/scauser.cpp b/src/ext/Util/ca/scauser.cpp index f92ebf1b..dc5bebba 100644 --- a/src/ext/Util/ca/scauser.cpp +++ b/src/ext/Util/ca/scauser.cpp | |||
| @@ -2,8 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | #include "precomp.h" | 3 | #include "precomp.h" |
| 4 | 4 | ||
| 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Password` FROM `Wix4User` WHERE `User`=?"; | 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Comment`, `Password` FROM `Wix4User` WHERE `User`=?"; |
| 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqPassword }; | 6 | enum eUserQuery { vuqUser = 1, vuqComponent, vuqName, vuqDomain, vuqComment, vuqPassword }; |
| 7 | 7 | ||
| 8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; | 8 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; |
| 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; |
| @@ -11,8 +11,8 @@ enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | |||
| 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; | 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; |
| 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; |
| 13 | 13 | ||
| 14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; | 14 | LPCWSTR vActionableQuery = L"SELECT `User`,`Component_`,`Name`,`Domain`,`Password`,`Comment`,`Attributes` FROM `Wix4User` WHERE `Component_` IS NOT NULL"; |
| 15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqAttributes }; | 15 | enum eActionableQuery { vaqUser = 1, vaqComponent, vaqName, vaqDomain, vaqPassword, vaqComment, vaqAttributes }; |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | static HRESULT AddUserToList( | 18 | static HRESULT AddUserToList( |
| @@ -78,6 +78,11 @@ HRESULT __stdcall ScaGetUser( | |||
| 78 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | 78 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); |
| 79 | ExitOnFailure(hr, "Failed to copy domain string to user object"); | 79 | ExitOnFailure(hr, "Failed to copy domain string to user object"); |
| 80 | 80 | ||
| 81 | hr = WcaGetRecordFormattedString(hRec, vuqComment, &pwzData); | ||
| 82 | ExitOnFailure(hr, "Failed to get Wix4User.Comment"); | ||
| 83 | hr = ::StringCchCopyW(pscau->wzComment, countof(pscau->wzComment), pwzData); | ||
| 84 | ExitOnFailure(hr, "Failed to copy comment string to user object"); | ||
| 85 | |||
| 81 | hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); | 86 | hr = WcaGetRecordFormattedString(hRec, vuqPassword, &pwzData); |
| 82 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); | 87 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); |
| 83 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | 88 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); |
| @@ -154,6 +159,11 @@ HRESULT __stdcall ScaGetUserDeferred( | |||
| 154 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); | 159 | hr = ::StringCchCopyW(pscau->wzDomain, countof(pscau->wzDomain), pwzData); |
| 155 | ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); | 160 | ExitOnFailure(hr, "Failed to copy domain string to user object (in deferred CA)"); |
| 156 | 161 | ||
| 162 | hr = WcaGetRecordString(hRec, vuqComment, &pwzData); | ||
| 163 | ExitOnFailure(hr, "Failed to get Wix4User.Comment"); | ||
| 164 | hr = ::StringCchCopyW(pscau->wzComment, countof(pscau->wzComment), pwzData); | ||
| 165 | ExitOnFailure(hr, "Failed to copy comment string to user object (in deferred CA)"); | ||
| 166 | |||
| 157 | hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); | 167 | hr = WcaGetRecordString(hRec, vuqPassword, &pwzData); |
| 158 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); | 168 | ExitOnFailure(hr, "Failed to get Wix4User.Password"); |
| 159 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); | 169 | hr = ::StringCchCopyW(pscau->wzPassword, countof(pscau->wzPassword), pwzData); |
| @@ -316,7 +326,7 @@ HRESULT ScaUserRead( | |||
| 316 | ExitOnFailure(hr, "failed to get Component state for Wix4User"); | 326 | ExitOnFailure(hr, "failed to get Component state for Wix4User"); |
| 317 | 327 | ||
| 318 | // don't bother if we aren't installing or uninstalling this component | 328 | // don't bother if we aren't installing or uninstalling this component |
| 319 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) | 329 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) |
| 320 | { | 330 | { |
| 321 | // | 331 | // |
| 322 | // Add the user to the list and populate it's values | 332 | // Add the user to the list and populate it's values |
| @@ -345,6 +355,10 @@ HRESULT ScaUserRead( | |||
| 345 | ExitOnFailure(hr, "failed to get Wix4User.Domain"); | 355 | ExitOnFailure(hr, "failed to get Wix4User.Domain"); |
| 346 | hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); | 356 | hr = ::StringCchCopyW(psu->wzDomain, countof(psu->wzDomain), pwzData); |
| 347 | ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); | 357 | ExitOnFailure(hr, "failed to copy user domain: %ls", pwzData); |
| 358 | hr = WcaGetRecordFormattedString(hRec, vaqComment, &pwzData); | ||
| 359 | ExitOnFailure(hr, "failed to get Wix4User.Comment"); | ||
| 360 | hr = ::StringCchCopyW(psu->wzComment, countof(psu->wzComment), pwzData); | ||
| 361 | ExitOnFailure(hr, "failed to copy user comment: %ls", pwzData); | ||
| 348 | 362 | ||
| 349 | hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); | 363 | hr = WcaGetRecordFormattedString(hRec, vaqPassword, &pwzData); |
| 350 | ExitOnFailure(hr, "failed to get Wix4User.Password"); | 364 | ExitOnFailure(hr, "failed to get Wix4User.Password"); |
| @@ -492,15 +506,16 @@ HRESULT ScaUserExecute( | |||
| 492 | { | 506 | { |
| 493 | USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; | 507 | USER_EXISTS ueUserExists = USER_EXISTS_INDETERMINATE; |
| 494 | 508 | ||
| 495 | // Always put the User Name and Domain plus Attributes on the front of the CustomAction | 509 | // Always put the User Name, Domain, and Comment on the front of the CustomAction data. |
| 496 | // data. Sometimes we'll add more data. | 510 | // The attributes will be added when we have finished adjusting them. Sometimes we'll |
| 511 | // add more data. | ||
| 497 | Assert(psu->wzName); | 512 | Assert(psu->wzName); |
| 498 | hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); | 513 | hr = WcaWriteStringToCaData(psu->wzName, &pwzActionData); |
| 499 | ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); | 514 | ExitOnFailure(hr, "Failed to add user name to custom action data: %ls", psu->wzName); |
| 500 | hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); | 515 | hr = WcaWriteStringToCaData(psu->wzDomain, &pwzActionData); |
| 501 | ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); | 516 | ExitOnFailure(hr, "Failed to add user domain to custom action data: %ls", psu->wzDomain); |
| 502 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | 517 | hr = WcaWriteStringToCaData(psu->wzComment, &pwzActionData); |
| 503 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | 518 | ExitOnFailure(hr, "Failed to add user comment to custom action data: %ls", psu->wzComment); |
| 504 | 519 | ||
| 505 | // Check to see if the user already exists since we have to be very careful when adding | 520 | // Check to see if the user already exists since we have to be very careful when adding |
| 506 | // and removing users. Note: MSDN says that it is safe to call these APIs from any | 521 | // and removing users. Note: MSDN says that it is safe to call these APIs from any |
| @@ -520,7 +535,12 @@ HRESULT ScaUserExecute( | |||
| 520 | } | 535 | } |
| 521 | if (ERROR_SUCCESS == er) | 536 | if (ERROR_SUCCESS == er) |
| 522 | { | 537 | { |
| 523 | wzDomain = pDomainControllerInfo->DomainControllerName + 2; //Add 2 so that we don't get the \\ prefix | 538 | if (2 <= wcslen(pDomainControllerInfo->DomainControllerName)) |
| 539 | { | ||
| 540 | wzDomain = pDomainControllerInfo->DomainControllerName + 2; // Add 2 so that we don't get the \\ prefix. | ||
| 541 | // Pass the entire string if it is too short | ||
| 542 | // to have a \\ prefix. | ||
| 543 | } | ||
| 524 | } | 544 | } |
| 525 | } | 545 | } |
| 526 | 546 | ||
| @@ -544,23 +564,32 @@ HRESULT ScaUserExecute( | |||
| 544 | 564 | ||
| 545 | if (WcaIsInstalling(psu->isInstalled, psu->isAction)) | 565 | if (WcaIsInstalling(psu->isInstalled, psu->isAction)) |
| 546 | { | 566 | { |
| 547 | // If the user exists, check to see if we are supposed to fail if user the exists before | 567 | // If the user exists, check to see if we are supposed to fail if the user exists before |
| 548 | // the install. | 568 | // the install. |
| 549 | if (USER_EXISTS_YES == ueUserExists) | 569 | if (USER_EXISTS_YES == ueUserExists) |
| 550 | { | 570 | { |
| 551 | // Reinstalls will always fail if we don't remove the check for "fail if exists". | 571 | // Re-installs will always fail if we don't remove the check for "fail if exists". |
| 552 | if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) | 572 | if (WcaIsReInstalling(psu->isInstalled, psu->isAction)) |
| 553 | { | 573 | { |
| 554 | psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; | 574 | psu->iAttributes &= ~SCAU_FAIL_IF_EXISTS; |
| 575 | |||
| 576 | // If install would create the user, re-install should be able to update the user. | ||
| 577 | if (!(psu->iAttributes & SCAU_DONT_CREATE_USER)) | ||
| 578 | { | ||
| 579 | psu->iAttributes |= SCAU_UPDATE_IF_EXISTS; | ||
| 580 | } | ||
| 555 | } | 581 | } |
| 556 | 582 | ||
| 557 | if ((SCAU_FAIL_IF_EXISTS & (psu->iAttributes)) && !(SCAU_UPDATE_IF_EXISTS & (psu->iAttributes))) | 583 | if (SCAU_FAIL_IF_EXISTS & psu->iAttributes && !(SCAU_UPDATE_IF_EXISTS & psu->iAttributes)) |
| 558 | { | 584 | { |
| 559 | hr = HRESULT_FROM_WIN32(NERR_UserExists); | 585 | hr = HRESULT_FROM_WIN32(NERR_UserExists); |
| 560 | MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); | 586 | MessageExitOnFailure(hr, msierrUSRFailedUserCreateExists, "Failed to create user: %ls because user already exists.", psu->wzName); |
| 561 | } | 587 | } |
| 562 | } | 588 | } |
| 563 | 589 | ||
| 590 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | ||
| 591 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | ||
| 592 | |||
| 564 | // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user | 593 | // Rollback only if the user already exists, we couldn't determine if the user exists, or we are going to create the user |
| 565 | if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) | 594 | if ((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists) || !(psu->iAttributes & SCAU_DONT_CREATE_USER)) |
| 566 | { | 595 | { |
| @@ -597,7 +626,6 @@ HRESULT ScaUserExecute( | |||
| 597 | ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); | 626 | ExitOnFailure(hr, "Failed to add user domain to rollback custom action data: %ls", psu->wzDomain); |
| 598 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); | 627 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); |
| 599 | ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); | 628 | ExitOnFailure(hr, "failed to add user attributes to rollback custom action data for user: %ls", psu->wzKey); |
| 600 | |||
| 601 | // If the user already exists, add relevant group information to rollback data | 629 | // If the user already exists, add relevant group information to rollback data |
| 602 | if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) | 630 | if (USER_EXISTS_YES == ueUserExists || USER_EXISTS_INDETERMINATE == ueUserExists) |
| 603 | { | 631 | { |
| @@ -630,11 +658,13 @@ HRESULT ScaUserExecute( | |||
| 630 | } | 658 | } |
| 631 | else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) | 659 | else if (((USER_EXISTS_YES == ueUserExists) || (USER_EXISTS_INDETERMINATE == ueUserExists)) && WcaIsUninstalling(psu->isInstalled, psu->isAction) && !(psu->iAttributes & SCAU_DONT_REMOVE_ON_UNINSTALL)) |
| 632 | { | 660 | { |
| 661 | hr = WcaWriteIntegerToCaData(psu->iAttributes, &pwzActionData); | ||
| 662 | ExitOnFailure(hr, "failed to add user attributes to custom action data for user: %ls", psu->wzKey); | ||
| 663 | |||
| 633 | // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted | 664 | // Add user's group information - this will ensure the user can be removed from any groups they were added to, if the user isn't be deleted |
| 634 | hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); | 665 | hr = WriteGroupInfo(psu->psgGroups, &pwzActionData); |
| 635 | ExitOnFailure(hr, "failed to add group information to custom action data"); | 666 | ExitOnFailure(hr, "failed to add group information to custom action data"); |
| 636 | 667 | ||
| 637 | // | ||
| 638 | // Schedule the removal because the user exists and we don't have any flags set | 668 | // Schedule the removal because the user exists and we don't have any flags set |
| 639 | // that say, don't remove the user on uninstall. | 669 | // that say, don't remove the user on uninstall. |
| 640 | // | 670 | // |
| @@ -642,7 +672,7 @@ HRESULT ScaUserExecute( | |||
| 642 | // CustomAction. | 672 | // CustomAction. |
| 643 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); | 673 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveUser"), pwzActionData, COST_USER_DELETE); |
| 644 | ExitOnFailure(hr, "failed to schedule RemoveUser"); | 674 | ExitOnFailure(hr, "failed to schedule RemoveUser"); |
| 645 | } | 675 | } |
| 646 | 676 | ||
| 647 | ReleaseNullStr(pwzScriptKey); | 677 | ReleaseNullStr(pwzScriptKey); |
| 648 | ReleaseNullStr(pwzActionData); | 678 | ReleaseNullStr(pwzActionData); |
diff --git a/src/ext/Util/ca/scauser.h b/src/ext/Util/ca/scauser.h index a5fd5ea8..3da847b5 100644 --- a/src/ext/Util/ca/scauser.h +++ b/src/ext/Util/ca/scauser.h | |||
| @@ -31,6 +31,7 @@ struct SCA_USER | |||
| 31 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | 31 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; |
| 32 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | 32 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; |
| 33 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; | 33 | WCHAR wzPassword[MAX_DARWIN_COLUMN + 1]; |
| 34 | WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; | ||
| 34 | INT iAttributes; | 35 | INT iAttributes; |
| 35 | 36 | ||
| 36 | SCA_GROUP *psgGroups; | 37 | SCA_GROUP *psgGroups; |
| @@ -41,16 +42,16 @@ struct SCA_USER | |||
| 41 | 42 | ||
| 42 | // prototypes | 43 | // prototypes |
| 43 | HRESULT __stdcall ScaGetUser( | 44 | HRESULT __stdcall ScaGetUser( |
| 44 | __in LPCWSTR wzUser, | 45 | __in LPCWSTR wzUser, |
| 45 | __out SCA_USER* pscau | 46 | __out SCA_USER* pscau |
| 46 | ); | 47 | ); |
| 47 | HRESULT __stdcall ScaGetUserDeferred( | 48 | HRESULT __stdcall ScaGetUserDeferred( |
| 48 | __in LPCWSTR wzUser, | 49 | __in LPCWSTR wzUser, |
| 49 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
| 50 | __out SCA_USER* pscau | 51 | __out SCA_USER* pscau |
| 51 | ); | 52 | ); |
| 52 | HRESULT __stdcall ScaGetGroup( | 53 | HRESULT __stdcall ScaGetGroup( |
| 53 | __in LPCWSTR wzGroup, | 54 | __in LPCWSTR wzGroup, |
| 54 | __out SCA_GROUP* pscag | 55 | __out SCA_GROUP* pscag |
| 55 | ); | 56 | ); |
| 56 | void ScaUserFreeList( | 57 | void ScaUserFreeList( |
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs new file mode 100644 index 00000000..af861986 --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/Package.wxs | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 2 | <Package Name="CreateUser" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
| 3 | <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> | ||
| 4 | |||
| 5 | <Feature Id="ProductFeature" Title="MsiPackage"> | ||
| 6 | <ComponentGroupRef Id="ProductComponents" /> | ||
| 7 | </Feature> | ||
| 8 | </Package> | ||
| 9 | |||
| 10 | <Fragment> | ||
| 11 | <StandardDirectory Id="ProgramFilesFolder"> | ||
| 12 | <Directory Id="INSTALLFOLDER" Name="CreateUser" /> | ||
| 13 | </StandardDirectory> | ||
| 14 | </Fragment> | ||
| 15 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs new file mode 100644 index 00000000..9fc7ba23 --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateUser/PackageComponents.wxs | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 3 | <Fragment> | ||
| 4 | <ComponentGroup Id="ProductComponents"> | ||
| 5 | <ComponentRef Id="Component1" /> | ||
| 6 | </ComponentGroup> | ||
| 7 | </Fragment> | ||
| 8 | <Fragment> | ||
| 9 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 10 | <util:User Id="TEST_USER00" Name="testName00" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 11 | <util:User Id="TEST_USER01" Name="testName01" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 12 | <util:User Id="TEST_USER02" Name="testName02" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 13 | <util:User Id="TEST_USER03" Name="testName03" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 14 | <util:User Id="TEST_USER04" Name="testName04" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 15 | <util:User Id="TEST_USER05" Name="testName05" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 16 | <util:User Id="TEST_USER06" Name="testName06" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 17 | <util:User Id="TEST_USER07" Name="testName07" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="no" /> | ||
| 18 | <util:User Id="TEST_USER10" Name="testName10" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 19 | <util:User Id="TEST_USER11" Name="testName11" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 20 | <util:User Id="TEST_USER12" Name="testName12" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 21 | <util:User Id="TEST_USER13" Name="testName13" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 22 | <util:User Id="TEST_USER14" Name="testName14" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 23 | <util:User Id="TEST_USER15" Name="testName15" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 24 | <util:User Id="TEST_USER16" Name="testName16" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 25 | <util:User Id="TEST_USER17" Name="testName17" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="no" /> | ||
| 26 | <util:User Id="TEST_USER20" Name="testName20" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 27 | <util:User Id="TEST_USER21" Name="testName21" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 28 | <util:User Id="TEST_USER22" Name="testName22" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 29 | <util:User Id="TEST_USER23" Name="testName23" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 30 | <util:User Id="TEST_USER24" Name="testName24" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 31 | <util:User Id="TEST_USER25" Name="testName25" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 32 | <util:User Id="TEST_USER26" Name="testName26" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 33 | <util:User Id="TEST_USER27" Name="testName27" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="no" /> | ||
| 34 | <util:User Id="TEST_USER30" Name="testName30" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 35 | <util:User Id="TEST_USER31" Name="testName31" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 36 | <util:User Id="TEST_USER32" Name="testName32" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 37 | <util:User Id="TEST_USER33" Name="testName33" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 38 | <util:User Id="TEST_USER34" Name="testName34" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 39 | <util:User Id="TEST_USER35" Name="testName35" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 40 | <util:User Id="TEST_USER36" Name="testName36" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 41 | <util:User Id="TEST_USER37" Name="testName37" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="no" /> | ||
| 42 | <util:User Id="TEST_USER40" Name="testName40" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 43 | <util:User Id="TEST_USER41" Name="testName41" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 44 | <util:User Id="TEST_USER42" Name="testName42" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 45 | <util:User Id="TEST_USER43" Name="testName43" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 46 | <util:User Id="TEST_USER44" Name="testName44" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 47 | <util:User Id="TEST_USER45" Name="testName45" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 48 | <util:User Id="TEST_USER46" Name="testName46" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 49 | <util:User Id="TEST_USER47" Name="testName47" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="no" RemoveOnUninstall="yes"/> | ||
| 50 | <util:User Id="TEST_USER50" Name="testName50" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 51 | <util:User Id="TEST_USER51" Name="testName51" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 52 | <util:User Id="TEST_USER52" Name="testName52" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 53 | <util:User Id="TEST_USER53" Name="testName53" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 54 | <util:User Id="TEST_USER54" Name="testName54" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 55 | <util:User Id="TEST_USER55" Name="testName55" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 56 | <util:User Id="TEST_USER56" Name="testName56" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 57 | <util:User Id="TEST_USER57" Name="testName57" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="no" RemoveOnUninstall="yes"/> | ||
| 58 | <util:User Id="TEST_USER60" Name="testName60" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 59 | <util:User Id="TEST_USER61" Name="testName61" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 60 | <util:User Id="TEST_USER62" Name="testName62" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 61 | <util:User Id="TEST_USER63" Name="testName63" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 62 | <util:User Id="TEST_USER64" Name="testName64" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 63 | <util:User Id="TEST_USER65" Name="testName65" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 64 | <util:User Id="TEST_USER66" Name="testName66" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 65 | <util:User Id="TEST_USER67" Name="testName67" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="no" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 66 | <util:User Id="TEST_USER70" Name="testName70" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 67 | <util:User Id="TEST_USER71" Name="testName71" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 68 | <util:User Id="TEST_USER72" Name="testName72" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 69 | <util:User Id="TEST_USER73" Name="testName73" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="no" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 70 | <util:User Id="TEST_USER74" Name="testName74" Password="test123!@#" PasswordExpired="no" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 71 | <util:User Id="TEST_USER75" Name="testName75" Password="test123!@#" PasswordExpired="yes" Comment="Test Comment 1" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 72 | <util:User Id="TEST_USER76" Name="testName76" Password="test123!@#" PasswordExpired="no" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 73 | <util:User Id="TEST_USER77" Name="testName77" Password="test123!@#" PasswordExpired="yes" RemoveComment="yes" CreateUser="yes" FailIfExists="yes" Vital="yes" RemoveOnUninstall="yes"/> | ||
| 74 | </Component> | ||
| 75 | </Fragment> | ||
| 76 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs index 24641fce..3da5f671 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs | |||
| @@ -297,6 +297,82 @@ namespace WixToolsetTest.Util | |||
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | [Fact] | 299 | [Fact] |
| 300 | public void CanCreateUserAccountWithComment() | ||
| 301 | { | ||
| 302 | var folder = TestData.Get(@"TestData\CreateUser"); | ||
| 303 | var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); | ||
| 304 | |||
| 305 | var results = build.BuildAndQuery(Build, "Wix4User"); | ||
| 306 | WixAssert.CompareLineByLine(new[] | ||
| 307 | { | ||
| 308 | "Wix4User:TEST_USER00\tComponent1\ttestName00\t\ttest123!@#\tTest Comment 1\t1792", | ||
| 309 | "Wix4User:TEST_USER01\tComponent1\ttestName01\t\ttest123!@#\tTest Comment 1\t1796", | ||
| 310 | "Wix4User:TEST_USER02\tComponent1\ttestName02\t\ttest123!@#\t\t3840", | ||
| 311 | "Wix4User:TEST_USER03\tComponent1\ttestName03\t\ttest123!@#\t\t3844", | ||
| 312 | "Wix4User:TEST_USER04\tComponent1\ttestName04\t\ttest123!@#\tTest Comment 1\t1280", | ||
| 313 | "Wix4User:TEST_USER05\tComponent1\ttestName05\t\ttest123!@#\tTest Comment 1\t1284", | ||
| 314 | "Wix4User:TEST_USER06\tComponent1\ttestName06\t\ttest123!@#\t\t3328", | ||
| 315 | "Wix4User:TEST_USER07\tComponent1\ttestName07\t\ttest123!@#\t\t3332", | ||
| 316 | "Wix4User:TEST_USER10\tComponent1\ttestName10\t\ttest123!@#\tTest Comment 1\t1808", | ||
| 317 | "Wix4User:TEST_USER11\tComponent1\ttestName11\t\ttest123!@#\tTest Comment 1\t1812", | ||
| 318 | "Wix4User:TEST_USER12\tComponent1\ttestName12\t\ttest123!@#\t\t3856", | ||
| 319 | "Wix4User:TEST_USER13\tComponent1\ttestName13\t\ttest123!@#\t\t3860", | ||
| 320 | "Wix4User:TEST_USER14\tComponent1\ttestName14\t\ttest123!@#\tTest Comment 1\t1296", | ||
| 321 | "Wix4User:TEST_USER15\tComponent1\ttestName15\t\ttest123!@#\tTest Comment 1\t1300", | ||
| 322 | "Wix4User:TEST_USER16\tComponent1\ttestName16\t\ttest123!@#\t\t3344", | ||
| 323 | "Wix4User:TEST_USER17\tComponent1\ttestName17\t\ttest123!@#\t\t3348", | ||
| 324 | "Wix4User:TEST_USER20\tComponent1\ttestName20\t\ttest123!@#\tTest Comment 1\t768", | ||
| 325 | "Wix4User:TEST_USER21\tComponent1\ttestName21\t\ttest123!@#\tTest Comment 1\t772", | ||
| 326 | "Wix4User:TEST_USER22\tComponent1\ttestName22\t\ttest123!@#\t\t2816", | ||
| 327 | "Wix4User:TEST_USER23\tComponent1\ttestName23\t\ttest123!@#\t\t2820", | ||
| 328 | "Wix4User:TEST_USER24\tComponent1\ttestName24\t\ttest123!@#\tTest Comment 1\t256", | ||
| 329 | "Wix4User:TEST_USER25\tComponent1\ttestName25\t\ttest123!@#\tTest Comment 1\t260", | ||
| 330 | "Wix4User:TEST_USER26\tComponent1\ttestName26\t\ttest123!@#\t\t2304", | ||
| 331 | "Wix4User:TEST_USER27\tComponent1\ttestName27\t\ttest123!@#\t\t2308", | ||
| 332 | "Wix4User:TEST_USER30\tComponent1\ttestName30\t\ttest123!@#\tTest Comment 1\t784", | ||
| 333 | "Wix4User:TEST_USER31\tComponent1\ttestName31\t\ttest123!@#\tTest Comment 1\t788", | ||
| 334 | "Wix4User:TEST_USER32\tComponent1\ttestName32\t\ttest123!@#\t\t2832", | ||
| 335 | "Wix4User:TEST_USER33\tComponent1\ttestName33\t\ttest123!@#\t\t2836", | ||
| 336 | "Wix4User:TEST_USER34\tComponent1\ttestName34\t\ttest123!@#\tTest Comment 1\t272", | ||
| 337 | "Wix4User:TEST_USER35\tComponent1\ttestName35\t\ttest123!@#\tTest Comment 1\t276", | ||
| 338 | "Wix4User:TEST_USER36\tComponent1\ttestName36\t\ttest123!@#\t\t2320", | ||
| 339 | "Wix4User:TEST_USER37\tComponent1\ttestName37\t\ttest123!@#\t\t2324", | ||
| 340 | "Wix4User:TEST_USER40\tComponent1\ttestName40\t\ttest123!@#\tTest Comment 1\t1536", | ||
| 341 | "Wix4User:TEST_USER41\tComponent1\ttestName41\t\ttest123!@#\tTest Comment 1\t1540", | ||
| 342 | "Wix4User:TEST_USER42\tComponent1\ttestName42\t\ttest123!@#\t\t3584", | ||
| 343 | "Wix4User:TEST_USER43\tComponent1\ttestName43\t\ttest123!@#\t\t3588", | ||
| 344 | "Wix4User:TEST_USER44\tComponent1\ttestName44\t\ttest123!@#\tTest Comment 1\t1024", | ||
| 345 | "Wix4User:TEST_USER45\tComponent1\ttestName45\t\ttest123!@#\tTest Comment 1\t1028", | ||
| 346 | "Wix4User:TEST_USER46\tComponent1\ttestName46\t\ttest123!@#\t\t3072", | ||
| 347 | "Wix4User:TEST_USER47\tComponent1\ttestName47\t\ttest123!@#\t\t3076", | ||
| 348 | "Wix4User:TEST_USER50\tComponent1\ttestName50\t\ttest123!@#\tTest Comment 1\t1552", | ||
| 349 | "Wix4User:TEST_USER51\tComponent1\ttestName51\t\ttest123!@#\tTest Comment 1\t1556", | ||
| 350 | "Wix4User:TEST_USER52\tComponent1\ttestName52\t\ttest123!@#\t\t3600", | ||
| 351 | "Wix4User:TEST_USER53\tComponent1\ttestName53\t\ttest123!@#\t\t3604", | ||
| 352 | "Wix4User:TEST_USER54\tComponent1\ttestName54\t\ttest123!@#\tTest Comment 1\t1040", | ||
| 353 | "Wix4User:TEST_USER55\tComponent1\ttestName55\t\ttest123!@#\tTest Comment 1\t1044", | ||
| 354 | "Wix4User:TEST_USER56\tComponent1\ttestName56\t\ttest123!@#\t\t3088", | ||
| 355 | "Wix4User:TEST_USER57\tComponent1\ttestName57\t\ttest123!@#\t\t3092", | ||
| 356 | "Wix4User:TEST_USER60\tComponent1\ttestName60\t\ttest123!@#\tTest Comment 1\t512", | ||
| 357 | "Wix4User:TEST_USER61\tComponent1\ttestName61\t\ttest123!@#\tTest Comment 1\t516", | ||
| 358 | "Wix4User:TEST_USER62\tComponent1\ttestName62\t\ttest123!@#\t\t2560", | ||
| 359 | "Wix4User:TEST_USER63\tComponent1\ttestName63\t\ttest123!@#\t\t2564", | ||
| 360 | "Wix4User:TEST_USER64\tComponent1\ttestName64\t\ttest123!@#\tTest Comment 1\t0", | ||
| 361 | "Wix4User:TEST_USER65\tComponent1\ttestName65\t\ttest123!@#\tTest Comment 1\t4", | ||
| 362 | "Wix4User:TEST_USER66\tComponent1\ttestName66\t\ttest123!@#\t\t2048", | ||
| 363 | "Wix4User:TEST_USER67\tComponent1\ttestName67\t\ttest123!@#\t\t2052", | ||
| 364 | "Wix4User:TEST_USER70\tComponent1\ttestName70\t\ttest123!@#\tTest Comment 1\t528", | ||
| 365 | "Wix4User:TEST_USER71\tComponent1\ttestName71\t\ttest123!@#\tTest Comment 1\t532", | ||
| 366 | "Wix4User:TEST_USER72\tComponent1\ttestName72\t\ttest123!@#\t\t2576", | ||
| 367 | "Wix4User:TEST_USER73\tComponent1\ttestName73\t\ttest123!@#\t\t2580", | ||
| 368 | "Wix4User:TEST_USER74\tComponent1\ttestName74\t\ttest123!@#\tTest Comment 1\t16", | ||
| 369 | "Wix4User:TEST_USER75\tComponent1\ttestName75\t\ttest123!@#\tTest Comment 1\t20", | ||
| 370 | "Wix4User:TEST_USER76\tComponent1\ttestName76\t\ttest123!@#\t\t2064", | ||
| 371 | "Wix4User:TEST_USER77\tComponent1\ttestName77\t\ttest123!@#\t\t2068", | ||
| 372 | }, results.OrderBy(s => s).ToArray()); | ||
| 373 | } | ||
| 374 | |||
| 375 | [Fact] | ||
| 300 | public void CanBuildBundleWithWarningsWithSearchesUsingDiscouragedVariableNames() | 376 | public void CanBuildBundleWithWarningsWithSearchesUsingDiscouragedVariableNames() |
| 301 | { | 377 | { |
| 302 | var folder = TestData.Get("TestData", "BundleWithSearches"); | 378 | var folder = TestData.Get("TestData", "BundleWithSearches"); |
diff --git a/src/ext/Util/wixext/Symbols/UserSymbol.cs b/src/ext/Util/wixext/Symbols/UserSymbol.cs index 5f00064b..6ea810de 100644 --- a/src/ext/Util/wixext/Symbols/UserSymbol.cs +++ b/src/ext/Util/wixext/Symbols/UserSymbol.cs | |||
| @@ -15,6 +15,7 @@ namespace WixToolset.Util | |||
| 15 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), | 15 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Name), IntermediateFieldType.String), |
| 16 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), | 16 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Domain), IntermediateFieldType.String), |
| 17 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), | 17 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Password), IntermediateFieldType.String), |
| 18 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Comment), IntermediateFieldType.String), | ||
| 18 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), | 19 | new IntermediateFieldDefinition(nameof(UserSymbolFields.Attributes), IntermediateFieldType.Number), |
| 19 | }, | 20 | }, |
| 20 | typeof(UserSymbol)); | 21 | typeof(UserSymbol)); |
| @@ -31,6 +32,7 @@ namespace WixToolset.Util.Symbols | |||
| 31 | Name, | 32 | Name, |
| 32 | Domain, | 33 | Domain, |
| 33 | Password, | 34 | Password, |
| 35 | Comment, | ||
| 34 | Attributes, | 36 | Attributes, |
| 35 | } | 37 | } |
| 36 | 38 | ||
| @@ -70,10 +72,16 @@ namespace WixToolset.Util.Symbols | |||
| 70 | set => this.Set((int)UserSymbolFields.Password, value); | 72 | set => this.Set((int)UserSymbolFields.Password, value); |
| 71 | } | 73 | } |
| 72 | 74 | ||
| 75 | public string Comment | ||
| 76 | { | ||
| 77 | get => this.Fields[(int)UserSymbolFields.Comment].AsString(); | ||
| 78 | set => this.Set((int)UserSymbolFields.Comment, value); | ||
| 79 | } | ||
| 80 | |||
| 73 | public int Attributes | 81 | public int Attributes |
| 74 | { | 82 | { |
| 75 | get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); | 83 | get => this.Fields[(int)UserSymbolFields.Attributes].AsNumber(); |
| 76 | set => this.Set((int)UserSymbolFields.Attributes, value); | 84 | set => this.Set((int)UserSymbolFields.Attributes, value); |
| 77 | } | 85 | } |
| 78 | } | 86 | } |
| 79 | } \ No newline at end of file | 87 | } |
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs index a6e4b835..d937b4f1 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs | |||
| @@ -34,6 +34,7 @@ namespace WixToolset.Util | |||
| 34 | internal const int UserDontRemoveOnUninstall = 0x00000100; | 34 | internal const int UserDontRemoveOnUninstall = 0x00000100; |
| 35 | internal const int UserDontCreateUser = 0x00000200; | 35 | internal const int UserDontCreateUser = 0x00000200; |
| 36 | internal const int UserNonVital = 0x00000400; | 36 | internal const int UserNonVital = 0x00000400; |
| 37 | internal const int UserRemoveComment = 0x00000800; | ||
| 37 | 38 | ||
| 38 | private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); | 39 | private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled); |
| 39 | 40 | ||
| @@ -3251,6 +3252,7 @@ namespace WixToolset.Util | |||
| 3251 | int attributes = 0; | 3252 | int attributes = 0; |
| 3252 | string domain = null; | 3253 | string domain = null; |
| 3253 | string name = null; | 3254 | string name = null; |
| 3255 | string comment = null; | ||
| 3254 | string password = null; | 3256 | string password = null; |
| 3255 | 3257 | ||
| 3256 | foreach (var attrib in element.Attributes()) | 3258 | foreach (var attrib in element.Attributes()) |
| @@ -3273,6 +3275,14 @@ namespace WixToolset.Util | |||
| 3273 | attributes |= UserPasswdCantChange; | 3275 | attributes |= UserPasswdCantChange; |
| 3274 | } | 3276 | } |
| 3275 | break; | 3277 | break; |
| 3278 | case "Comment": | ||
| 3279 | if (null == componentId) | ||
| 3280 | { | ||
| 3281 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 3282 | } | ||
| 3283 | |||
| 3284 | comment = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 3285 | break; | ||
| 3276 | case "CreateUser": | 3286 | case "CreateUser": |
| 3277 | if (null == componentId) | 3287 | if (null == componentId) |
| 3278 | { | 3288 | { |
| @@ -3357,6 +3367,12 @@ namespace WixToolset.Util | |||
| 3357 | attributes |= UserDontExpirePasswrd; | 3367 | attributes |= UserDontExpirePasswrd; |
| 3358 | } | 3368 | } |
| 3359 | break; | 3369 | break; |
| 3370 | case "RemoveComment": | ||
| 3371 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 3372 | { | ||
| 3373 | attributes |= UserRemoveComment; | ||
| 3374 | } | ||
| 3375 | break; | ||
| 3360 | case "RemoveOnUninstall": | 3376 | case "RemoveOnUninstall": |
| 3361 | if (null == componentId) | 3377 | if (null == componentId) |
| 3362 | { | 3378 | { |
| @@ -3411,6 +3427,11 @@ namespace WixToolset.Util | |||
| 3411 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); | 3427 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); |
| 3412 | } | 3428 | } |
| 3413 | 3429 | ||
| 3430 | if (null != comment && (UserRemoveComment & attributes) != 0) | ||
| 3431 | { | ||
| 3432 | this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Comment", "RemoveComment")); | ||
| 3433 | } | ||
| 3434 | |||
| 3414 | foreach (var child in element.Elements()) | 3435 | foreach (var child in element.Elements()) |
| 3415 | { | 3436 | { |
| 3416 | if (this.Namespace == child.Name.Namespace) | 3437 | if (this.Namespace == child.Name.Namespace) |
| @@ -3450,6 +3471,7 @@ namespace WixToolset.Util | |||
| 3450 | Name = name, | 3471 | Name = name, |
| 3451 | Domain = domain, | 3472 | Domain = domain, |
| 3452 | Password = password, | 3473 | Password = password, |
| 3474 | Comment = comment, | ||
| 3453 | Attributes = attributes, | 3475 | Attributes = attributes, |
| 3454 | }); | 3476 | }); |
| 3455 | } | 3477 | } |
diff --git a/src/ext/Util/wixext/UtilDecompiler.cs b/src/ext/Util/wixext/UtilDecompiler.cs index 7d95fcef..1201fdd5 100644 --- a/src/ext/Util/wixext/UtilDecompiler.cs +++ b/src/ext/Util/wixext/UtilDecompiler.cs | |||
| @@ -559,13 +559,14 @@ namespace WixToolset.Util | |||
| 559 | { | 559 | { |
| 560 | foreach (var row in table.Rows) | 560 | foreach (var row in table.Rows) |
| 561 | { | 561 | { |
| 562 | var attributes = row.FieldAsNullableInteger(5) ?? 0; | 562 | var attributes = row.FieldAsNullableInteger(6) ?? 0; |
| 563 | 563 | ||
| 564 | var user = new XElement(UtilConstants.UserName, | 564 | var user = new XElement(UtilConstants.UserName, |
| 565 | new XAttribute("Id", row.FieldAsString(0)), | 565 | new XAttribute("Id", row.FieldAsString(0)), |
| 566 | new XAttribute("Name", row.FieldAsString(2)), | 566 | new XAttribute("Name", row.FieldAsString(2)), |
| 567 | AttributeIfNotNull("Domain", row, 3), | 567 | AttributeIfNotNull("Domain", row, 3), |
| 568 | AttributeIfNotNull("Password", row, 4), | 568 | AttributeIfNotNull("Password", row, 4), |
| 569 | AttributeIfNotNull("Comment", row, 5), | ||
| 569 | AttributeIfTrue("PasswordNeverExpires", UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)), | 570 | AttributeIfTrue("PasswordNeverExpires", UtilCompiler.UserDontExpirePasswrd == (attributes & UtilCompiler.UserDontExpirePasswrd)), |
| 570 | AttributeIfTrue("CanNotChangePassword", UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)), | 571 | AttributeIfTrue("CanNotChangePassword", UtilCompiler.UserPasswdCantChange == (attributes & UtilCompiler.UserPasswdCantChange)), |
| 571 | AttributeIfTrue("PasswordExpired", UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)), | 572 | AttributeIfTrue("PasswordExpired", UtilCompiler.UserPasswdChangeReqdOnLogin == (attributes & UtilCompiler.UserPasswdChangeReqdOnLogin)), |
| @@ -573,7 +574,8 @@ namespace WixToolset.Util | |||
| 573 | AttributeIfTrue("FailIfExists", UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)), | 574 | AttributeIfTrue("FailIfExists", UtilCompiler.UserFailIfExists == (attributes & UtilCompiler.UserFailIfExists)), |
| 574 | AttributeIfTrue("UpdateIfExists", UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)), | 575 | AttributeIfTrue("UpdateIfExists", UtilCompiler.UserUpdateIfExists == (attributes & UtilCompiler.UserUpdateIfExists)), |
| 575 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)), | 576 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)), |
| 576 | AttributeIfTrue("LogonAsService", UtilCompiler.UserLogonAsService == (attributes & UtilCompiler.UserLogonAsService)) | 577 | AttributeIfTrue("LogonAsBatchJob", UtilCompiler.UserLogonAsBatchJob == (attributes & UtilCompiler.UserLogonAsBatchJob)), |
| 578 | AttributeIfTrue("RemoveComment", UtilCompiler.UserRemoveComment == (attributes & UtilCompiler.UserRemoveComment)) | ||
| 577 | ); | 579 | ); |
| 578 | 580 | ||
| 579 | if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) | 581 | if (UtilCompiler.UserDontRemoveOnUninstall == (attributes & UtilCompiler.UserDontRemoveOnUninstall)) |
diff --git a/src/ext/Util/wixext/UtilTableDefinitions.cs b/src/ext/Util/wixext/UtilTableDefinitions.cs index 57c18b6c..33e6d3d1 100644 --- a/src/ext/Util/wixext/UtilTableDefinitions.cs +++ b/src/ext/Util/wixext/UtilTableDefinitions.cs | |||
| @@ -229,6 +229,7 @@ namespace WixToolset.Util | |||
| 229 | new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), | 229 | new ColumnDefinition("Name", ColumnType.String, 255, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "User name", modularizeType: ColumnModularizeType.Property), |
| 230 | new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), | 230 | new ColumnDefinition("Domain", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User domain", modularizeType: ColumnModularizeType.Property), |
| 231 | new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), | 231 | new ColumnDefinition("Password", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User password", modularizeType: ColumnModularizeType.Property), |
| 232 | new ColumnDefinition("Comment", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "User comment", modularizeType: ColumnModularizeType.Property), | ||
| 232 | new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), | 233 | new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the user"), |
| 233 | }, | 234 | }, |
| 234 | symbolIdIsPrimaryKey: true | 235 | symbolIdIsPrimaryKey: true |
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp b/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp index 2b68f36f..86b7602e 100644 --- a/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp +++ b/src/libs/wcautil/WixToolset.WcaUtil/wcawrap.cpp | |||
| @@ -906,7 +906,7 @@ static void RevealNulls( | |||
| 906 | 906 | ||
| 907 | 907 | ||
| 908 | /******************************************************************** | 908 | /******************************************************************** |
| 909 | WcaGetRecordFormattedString() - gets formatted string filed from record | 909 | WcaGetRecordFormattedString() - gets formatted string field from record |
| 910 | 910 | ||
| 911 | ********************************************************************/ | 911 | ********************************************************************/ |
| 912 | extern "C" HRESULT WIXAPI WcaGetRecordFormattedString( | 912 | extern "C" HRESULT WIXAPI WcaGetRecordFormattedString( |
| @@ -1391,9 +1391,14 @@ extern "C" HRESULT WIXAPI WcaWriteIntegerToCaData( | |||
| 1391 | ) | 1391 | ) |
| 1392 | { | 1392 | { |
| 1393 | WCHAR wzBuffer[13]; | 1393 | WCHAR wzBuffer[13]; |
| 1394 | StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%d", i); | 1394 | HRESULT hr = StringCchPrintfW(wzBuffer, countof(wzBuffer), L"%d", i); |
| 1395 | ExitOnFailure(hr, "failed to write integer to ca data"); | ||
| 1395 | 1396 | ||
| 1396 | return WcaWriteStringToCaData(wzBuffer, ppwzCustomActionData); | 1397 | hr = WcaWriteStringToCaData(wzBuffer, ppwzCustomActionData); |
| 1398 | ExitOnFailure(hr, "failed to write integer to ca data"); | ||
| 1399 | |||
| 1400 | LExit: | ||
| 1401 | return hr; | ||
| 1397 | } | 1402 | } |
| 1398 | 1403 | ||
| 1399 | 1404 | ||
diff --git a/src/test/burn/WixTestTools/MSIExec.cs b/src/test/burn/WixTestTools/MSIExec.cs index a905ec5a..fb161495 100644 --- a/src/test/burn/WixTestTools/MSIExec.cs +++ b/src/test/burn/WixTestTools/MSIExec.cs | |||
| @@ -259,7 +259,7 @@ namespace WixTestTools | |||
| 259 | arguments.Append(" /a "); | 259 | arguments.Append(" /a "); |
| 260 | break; | 260 | break; |
| 261 | case MSIExecMode.Repair: | 261 | case MSIExecMode.Repair: |
| 262 | arguments.Append(" /f "); | 262 | arguments.Append(" /fvomusa "); |
| 263 | break; | 263 | break; |
| 264 | case MSIExecMode.Cleanup: | 264 | case MSIExecMode.Cleanup: |
| 265 | case MSIExecMode.Uninstall: | 265 | case MSIExecMode.Uninstall: |
diff --git a/src/test/burn/WixTestTools/UserVerifier.cs b/src/test/burn/WixTestTools/UserVerifier.cs index b5218a79..51c6c31e 100644 --- a/src/test/burn/WixTestTools/UserVerifier.cs +++ b/src/test/burn/WixTestTools/UserVerifier.cs | |||
| @@ -49,7 +49,7 @@ namespace WixTestTools | |||
| 49 | UserPrincipal newUser = new UserPrincipal(new PrincipalContext(ContextType.Machine)); | 49 | UserPrincipal newUser = new UserPrincipal(new PrincipalContext(ContextType.Machine)); |
| 50 | newUser.SetPassword(password); | 50 | newUser.SetPassword(password); |
| 51 | newUser.Name = userName; | 51 | newUser.Name = userName; |
| 52 | newUser.Description = "New test User"; | 52 | newUser.Description = String.Empty; |
| 53 | newUser.UserCannotChangePassword = true; | 53 | newUser.UserCannotChangePassword = true; |
| 54 | newUser.PasswordNeverExpires = false; | 54 | newUser.PasswordNeverExpires = false; |
| 55 | newUser.Save(); | 55 | newUser.Save(); |
| @@ -109,6 +109,24 @@ namespace WixTestTools | |||
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | /// <summary> | 111 | /// <summary> |
| 112 | /// Sets the user comment for a given user | ||
| 113 | /// </summary> | ||
| 114 | /// <param name="domainName">domain name for the user, empty for local users</param> | ||
| 115 | /// <param name="userName">the user name</param> | ||
| 116 | /// <param name="comment">comment to be set for the user</param> | ||
| 117 | public static void SetUserComment(string domainName, string userName, string comment) | ||
| 118 | { | ||
| 119 | UserPrincipal user = GetUser(domainName, userName); | ||
| 120 | |||
| 121 | Assert.False(null == user, String.Format("User '{0}' was not found under domain '{1}'.", userName, domainName)); | ||
| 122 | |||
| 123 | var directoryEntry = user.GetUnderlyingObject() as DirectoryEntry; | ||
| 124 | Assert.False(null == directoryEntry); | ||
| 125 | directoryEntry.Properties["Description"].Value = comment; | ||
| 126 | user.Save(); | ||
| 127 | } | ||
| 128 | |||
| 129 | /// <summary> | ||
| 112 | /// Adds the specified user to the specified local group | 130 | /// Adds the specified user to the specified local group |
| 113 | /// </summary> | 131 | /// </summary> |
| 114 | /// <param name="userName">User to add</param> | 132 | /// <param name="userName">User to add</param> |
| @@ -162,7 +180,24 @@ namespace WixTestTools | |||
| 162 | } | 180 | } |
| 163 | 181 | ||
| 164 | /// <summary> | 182 | /// <summary> |
| 165 | /// Verify that a givin user is member of a local group | 183 | /// Verifies the user comment for a given user |
| 184 | /// </summary> | ||
| 185 | /// <param name="domainName">domain name for the user, empty for local users</param> | ||
| 186 | /// <param name="userName">the user name</param> | ||
| 187 | /// <param name="comment">the comment to be verified</param> | ||
| 188 | public static void VerifyUserComment(string domainName, string userName, string comment) | ||
| 189 | { | ||
| 190 | UserPrincipal user = GetUser(domainName, userName); | ||
| 191 | |||
| 192 | Assert.False(null == user, String.Format("User '{0}' was not found under domain '{1}'.", userName, domainName)); | ||
| 193 | |||
| 194 | var directoryEntry = user.GetUnderlyingObject() as DirectoryEntry; | ||
| 195 | Assert.False(null == directoryEntry); | ||
| 196 | Assert.True(comment == (string)(directoryEntry.Properties["Description"].Value)); | ||
| 197 | } | ||
| 198 | |||
| 199 | /// <summary> | ||
| 200 | /// Verify that a given user is member of a local group | ||
| 166 | /// </summary> | 201 | /// </summary> |
| 167 | /// <param name="domainName">domain name for the user, empty for local users</param> | 202 | /// <param name="domainName">domain name for the user, empty for local users</param> |
| 168 | /// <param name="userName">the user name</param> | 203 | /// <param name="userName">the user name</param> |
| @@ -322,7 +357,6 @@ namespace WixTestTools | |||
| 322 | missedAGroup = true; | 357 | missedAGroup = true; |
| 323 | message += String.Format("Local group '{0}' was not found. \r\n", groupName); | 358 | message += String.Format("Local group '{0}' was not found. \r\n", groupName); |
| 324 | } | 359 | } |
| 325 | |||
| 326 | } | 360 | } |
| 327 | Assert.False(missedAGroup, message); | 361 | Assert.False(missedAGroup, message); |
| 328 | } | 362 | } |
| @@ -346,3 +380,4 @@ namespace WixTestTools | |||
| 346 | } | 380 | } |
| 347 | } | 381 | } |
| 348 | } | 382 | } |
| 383 | |||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj index fbc6f292..3895b853 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/ProductA.wixproj | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> |
| 2 | <Project Sdk="WixToolset.Sdk"> | 2 | <Project Sdk="WixToolset.Sdk"> |
| 3 | <PropertyGroup> | 3 | <PropertyGroup> |
| 4 | <UpgradeCode>{1A1795A6-87C0-4A9A-ABD5-DF9BED697037}</UpgradeCode> | 4 | <UpgradeCode>{A3E0B539-63F9-4B43-9E34-F33AE1C6E06D}</UpgradeCode> |
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | 5 | <ProductComponentsRef>true</ProductComponentsRef> |
| 6 | </PropertyGroup> | 6 | </PropertyGroup> |
| 7 | <ItemGroup> | 7 | <ItemGroup> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs index a7bec54e..be6e16a4 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductA/product.wxs | |||
| @@ -15,10 +15,10 @@ | |||
| 15 | <util:Group Id="ADMIN" Name="Administrators" /> | 15 | <util:Group Id="ADMIN" Name="Administrators" /> |
| 16 | <util:Group Id="POWER_USER" Name="Power Users" /> | 16 | <util:Group Id="POWER_USER" Name="Power Users" /> |
| 17 | 17 | ||
| 18 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | 18 | <Component Id="Component1" Guid="09624A9A-4BBC-4126-BBF9-0713C5217DB1" Directory="INSTALLFOLDER"> |
| 19 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | 19 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> |
| 20 | 20 | ||
| 21 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes"> | 21 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" CreateUser="yes" RemoveOnUninstall="yes"> |
| 22 | <util:GroupRef Id="ADMIN" /> | 22 | <util:GroupRef Id="ADMIN" /> |
| 23 | <util:GroupRef Id="POWER_USER" /> | 23 | <util:GroupRef Id="POWER_USER" /> |
| 24 | </util:User> | 24 | </util:User> |
| @@ -27,7 +27,7 @@ | |||
| 27 | <util:GroupRef Id="POWER_USER" /> | 27 | <util:GroupRef Id="POWER_USER" /> |
| 28 | </util:User> | 28 | </util:User> |
| 29 | 29 | ||
| 30 | <util:User Id="TEST_USER3" Name="[TEMPUSERNAME]" Domain="[TEMPDOMAIN]" CreateUser="no"> | 30 | <util:User Id="TEST_USER3" Name="testName3" CreateUser="no"> |
| 31 | <util:GroupRef Id="POWER_USER" /> | 31 | <util:GroupRef Id="POWER_USER" /> |
| 32 | </util:User> | 32 | </util:User> |
| 33 | </Component> | 33 | </Component> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj new file mode 100644 index 00000000..5938e525 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/ProductAddCommentToExistingUser.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{B33D3140-4AA5-469D-9DEE-AAF8F0C626DA}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs new file mode 100644 index 00000000..ce8c4cae --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductAddCommentToExistingUser/product.wxs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | |||
| 15 | <util:User Id="TEST_USER1" | ||
| 16 | Name="testName1" | ||
| 17 | Password="test123!@#" | ||
| 18 | PasswordExpired="yes" | ||
| 19 | CreateUser="yes" | ||
| 20 | UpdateIfExists="yes" | ||
| 21 | RemoveOnUninstall="yes" | ||
| 22 | Comment="testComment1"/> | ||
| 23 | </Component> | ||
| 24 | </Fragment> | ||
| 25 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj new file mode 100644 index 00000000..63bb2370 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/ProductCommentDelete.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{9E4C301E-5F36-4A86-85BE-776E067D929D}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs new file mode 100644 index 00000000..f0fbc55e --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentDelete/product.wxs | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | |||
| 15 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" RemoveComment="yes"/> | ||
| 16 | </Component> | ||
| 17 | </Fragment> | ||
| 18 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj new file mode 100644 index 00000000..66f308ae --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/ProductCommentFail.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{85F698E0-F542-4CB4-80A1-6630D2DEB647}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs new file mode 100644 index 00000000..f36d5bd5 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductCommentFail/product_fail.wxs | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | |||
| 10 | <InstallExecuteSequence> | ||
| 11 | <Custom Action="CaFail" After="Wix4ConfigureUsers_X86" /> | ||
| 12 | </InstallExecuteSequence> | ||
| 13 | </Fragment> | ||
| 14 | |||
| 15 | <Fragment> | ||
| 16 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 17 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 18 | |||
| 19 | <util:User Id="TEST_USER1" Name="testName1" Password="test123!@#" PasswordExpired="yes" CreateUser="yes" RemoveOnUninstall="yes" Comment="testComment1"/> | ||
| 20 | </Component> | ||
| 21 | </Fragment> | ||
| 22 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs index c5da862c..82472d4e 100644 --- a/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductFail/product_fail.wxs | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | <util:GroupRef Id="POWER_USER" /> | 31 | <util:GroupRef Id="POWER_USER" /> |
| 32 | </util:User> | 32 | </util:User> |
| 33 | 33 | ||
| 34 | <util:User Id="TEST_USER3" Name="[TEMPUSERNAME]" Domain="[TEMPDOMAIN]" CreateUser="no"> | 34 | <util:User Id="TEST_USER3" Name="testName3" CreateUser="no"> |
| 35 | <util:GroupRef Id="POWER_USER" /> | 35 | <util:GroupRef Id="POWER_USER" /> |
| 36 | </util:User> | 36 | </util:User> |
| 37 | </Component> | 37 | </Component> |
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj new file mode 100644 index 00000000..aeac903a --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/ProductNewUserWithComment.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{549E1829-BBDE-42E1-968A-BEB8FC12BFC7}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs new file mode 100644 index 00000000..dde23aab --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductNewUserWithComment/product.wxs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | |||
| 3 | |||
| 4 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 5 | <Fragment> | ||
| 6 | <ComponentGroup Id="ProductComponents"> | ||
| 7 | <ComponentRef Id="Component1" /> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | |||
| 11 | <Fragment> | ||
| 12 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 13 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 14 | <util:User | ||
| 15 | Id="TEST_USER1" | ||
| 16 | Name="testName1" | ||
| 17 | Password="test123!@#" | ||
| 18 | PasswordExpired="yes" | ||
| 19 | CreateUser="yes" | ||
| 20 | UpdateIfExists="yes" | ||
| 21 | RemoveOnUninstall="yes" | ||
| 22 | Comment="testComment1" /> | ||
| 23 | </Component> | ||
| 24 | </Fragment> | ||
| 25 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj new file mode 100644 index 00000000..93a56216 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Project Sdk="WixToolset.Sdk"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <UpgradeCode>{79F2CB65-1E71-42EB-AA30-51BD70C29B23}</UpgradeCode> | ||
| 5 | <ProductComponentsRef>true</ProductComponentsRef> | ||
| 6 | </PropertyGroup> | ||
| 7 | <ItemGroup> | ||
| 8 | <Compile Include="..\..\Templates\Product.wxs" Link="Product.wxs" /> | ||
| 9 | </ItemGroup> | ||
| 10 | <ItemGroup> | ||
| 11 | <PackageReference Include="WixToolset.Util.wixext" /> | ||
| 12 | </ItemGroup> | ||
| 13 | </Project> | ||
diff --git a/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs new file mode 100644 index 00000000..564ce4f0 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionUserTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | <!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. --> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 3 | <Fragment> | ||
| 4 | <ComponentGroup Id="ProductComponents"> | ||
| 5 | <ComponentRef Id="Component1" /> | ||
| 6 | </ComponentGroup> | ||
| 7 | </Fragment> | ||
| 8 | |||
| 9 | <Fragment> | ||
| 10 | <Component Id="Component1" | ||
| 11 | Guid="1FDC6C4D-7741-4BF1-A4F0-4231879CEC45" | ||
| 12 | Directory="INSTALLFOLDER"> | ||
| 13 | <util:User Id="TEST_USER1" | ||
| 14 | Name="[TESTPARAMETER1]" | ||
| 15 | Password="test123!@#" | ||
| 16 | PasswordExpired="yes" | ||
| 17 | CreateUser="yes" | ||
| 18 | RemoveOnUninstall="yes" /> | ||
| 19 | </Component> | ||
| 20 | </Fragment> | ||
| 21 | </Wix> | ||
diff --git a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs index fcdfde52..30bc53e8 100644 --- a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs +++ b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionUserTests.cs | |||
| @@ -11,21 +11,14 @@ namespace WixToolsetTest.MsiE2E | |||
| 11 | { | 11 | { |
| 12 | public UtilExtensionUserTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | 12 | public UtilExtensionUserTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } |
| 13 | 13 | ||
| 14 | const string TempDomain = "USERDOMAIN"; | ||
| 15 | const string TempUsername = "USERNAME"; | ||
| 16 | |||
| 17 | // Verify that the users specified in the authoring are created as expected. | 14 | // Verify that the users specified in the authoring are created as expected. |
| 18 | [RuntimeFact] | 15 | [RuntimeFact] |
| 19 | public void CanInstallAndUninstallUsers() | 16 | public void CanInstallAndUninstallUsers() |
| 20 | { | 17 | { |
| 21 | var arguments = new string[] | 18 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); |
| 22 | { | ||
| 23 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | ||
| 24 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 25 | }; | ||
| 26 | var productA = this.CreatePackageInstaller("ProductA"); | 19 | var productA = this.CreatePackageInstaller("ProductA"); |
| 27 | 20 | ||
| 28 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 21 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 29 | 22 | ||
| 30 | // Validate New User Information. | 23 | // Validate New User Information. |
| 31 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); | 24 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); |
| @@ -34,62 +27,90 @@ namespace WixToolsetTest.MsiE2E | |||
| 34 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); | 27 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); |
| 35 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); | 28 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); |
| 36 | 29 | ||
| 37 | UserVerifier.VerifyUserIsMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 30 | UserVerifier.VerifyUserIsMemberOf("", "testName3", "Power Users"); |
| 38 | 31 | ||
| 39 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 32 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 40 | 33 | ||
| 41 | // Verify Users marked as RemoveOnUninstall were removed. | 34 | // Verify Users marked as RemoveOnUninstall were removed. |
| 42 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); | 35 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); |
| 43 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); | 36 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); |
| 44 | 37 | ||
| 38 | // Verify that user added to power users group is removed on uninstall. | ||
| 39 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 40 | |||
| 45 | // clean up | 41 | // clean up |
| 42 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 46 | UserVerifier.DeleteLocalUser("testName2"); | 43 | UserVerifier.DeleteLocalUser("testName2"); |
| 47 | 44 | UserVerifier.DeleteLocalUser("testName3"); | |
| 48 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | // Verify the rollback action reverts all Users changes. | 47 | // Verify the rollback action reverts all Users changes. |
| 52 | [RuntimeFact] | 48 | [RuntimeFact] |
| 53 | public void CanRollbackUsers() | 49 | public void CanRollbackUsers() |
| 54 | { | 50 | { |
| 55 | var arguments = new string[] | 51 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); |
| 56 | { | ||
| 57 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | ||
| 58 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 59 | }; | ||
| 60 | var productFail = this.CreatePackageInstaller("ProductFail"); | 52 | var productFail = this.CreatePackageInstaller("ProductFail"); |
| 61 | 53 | ||
| 62 | // make sure the user accounts are deleted before we start | 54 | // make sure the user accounts are deleted before we start |
| 63 | UserVerifier.DeleteLocalUser("testName1"); | 55 | UserVerifier.DeleteLocalUser("testName1"); |
| 64 | UserVerifier.DeleteLocalUser("testName2"); | 56 | UserVerifier.DeleteLocalUser("testName2"); |
| 65 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 66 | 57 | ||
| 67 | productFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, arguments); | 58 | productFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); |
| 68 | 59 | ||
| 69 | // Verify Users marked as RemoveOnUninstall were removed. | 60 | // Verify added Users were removed on rollback. |
| 70 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Rollback", "testName1")); | 61 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Rollback", "testName1")); |
| 71 | Assert.False(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was not removed on Rollback", "testName2")); | 62 | Assert.False(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was not removed on Rollback", "testName2")); |
| 72 | 63 | ||
| 73 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 64 | // Verify that user added to power users group is removed from power users group on rollback. |
| 65 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 66 | |||
| 67 | // clean up | ||
| 68 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 69 | UserVerifier.DeleteLocalUser("testName2"); | ||
| 70 | UserVerifier.DeleteLocalUser("testName3"); | ||
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | // Verify that the users specified in the authoring are created as expected on repair. | 73 | |
| 77 | [RuntimeFact(Skip = "Test demonstrates failure")] | 74 | // Verify that command-line parameters aer not blocked by repair switches. |
| 78 | public void CanRepairUsers() | 75 | // Original code signalled repair mode by using "-f ", which silently |
| 76 | // terminated the command-line parsing, ignoring any parameters that followed. | ||
| 77 | [RuntimeFact()] | ||
| 78 | public void CanRepairUsersWithCommandLineParameters() | ||
| 79 | { | 79 | { |
| 80 | var arguments = new string[] | 80 | var arguments = new string[] |
| 81 | { | 81 | { |
| 82 | $"TEMPDOMAIN={Environment.GetEnvironmentVariable(TempDomain)}", | 82 | "TESTPARAMETER1=testName1", |
| 83 | $"TEMPUSERNAME={Environment.GetEnvironmentVariable(TempUsername)}", | ||
| 84 | }; | 83 | }; |
| 84 | var productWithCommandLineParameters = this.CreatePackageInstaller("ProductWithCommandLineParameters"); | ||
| 85 | |||
| 86 | // Make sure that the user doesn't exist when we start the test. | ||
| 87 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 88 | |||
| 89 | // Install | ||
| 90 | productWithCommandLineParameters.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 91 | |||
| 92 | // Repair | ||
| 93 | productWithCommandLineParameters.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 94 | |||
| 95 | // Clean up | ||
| 96 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 97 | } | ||
| 98 | |||
| 99 | |||
| 100 | // Verify that the users specified in the authoring are created as expected on repair. | ||
| 101 | [RuntimeFact()] | ||
| 102 | public void CanRepairUsers() | ||
| 103 | { | ||
| 104 | UserVerifier.CreateLocalUser("testName3", "test123!@#"); | ||
| 85 | var productA = this.CreatePackageInstaller("ProductA"); | 105 | var productA = this.CreatePackageInstaller("ProductA"); |
| 86 | 106 | ||
| 87 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 107 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 88 | 108 | ||
| 109 | // Validate New User Information. | ||
| 89 | UserVerifier.DeleteLocalUser("testName1"); | 110 | UserVerifier.DeleteLocalUser("testName1"); |
| 90 | UserVerifier.SetUserInformation(String.Empty, "testName2", true, false, false); | 111 | UserVerifier.SetUserInformation(String.Empty, "testName2", true, false, false); |
| 91 | 112 | ||
| 92 | productA.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 113 | productA.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 93 | 114 | ||
| 94 | // Validate New User Information. | 115 | // Validate New User Information. |
| 95 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); | 116 | UserVerifier.VerifyUserInformation(String.Empty, "testName1", true, false, false); |
| @@ -98,21 +119,24 @@ namespace WixToolsetTest.MsiE2E | |||
| 98 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); | 119 | UserVerifier.VerifyUserInformation(String.Empty, "testName2", true, true, true); |
| 99 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); | 120 | UserVerifier.VerifyUserIsMemberOf(String.Empty, "testName2", "Power Users"); |
| 100 | 121 | ||
| 101 | UserVerifier.VerifyUserIsMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | 122 | UserVerifier.VerifyUserIsMemberOf("", "testName3", "Power Users"); |
| 102 | 123 | ||
| 103 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | 124 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); |
| 104 | 125 | ||
| 105 | // Verify Users marked as RemoveOnUninstall were removed. | 126 | // Verify Users marked as RemoveOnUninstall were removed. |
| 106 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); | 127 | Assert.False(UserVerifier.UserExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); |
| 107 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); | 128 | Assert.True(UserVerifier.UserExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); |
| 108 | 129 | ||
| 130 | // Verify that user added to power users group is removed on uninstall. | ||
| 131 | UserVerifier.VerifyUserIsNotMemberOf("", "testName3", "Power Users"); | ||
| 132 | |||
| 109 | // clean up | 133 | // clean up |
| 134 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 110 | UserVerifier.DeleteLocalUser("testName2"); | 135 | UserVerifier.DeleteLocalUser("testName2"); |
| 111 | 136 | UserVerifier.DeleteLocalUser("testName3"); | |
| 112 | UserVerifier.VerifyUserIsNotMemberOf(Environment.GetEnvironmentVariable(TempDomain), Environment.GetEnvironmentVariable(TempUsername), "Power Users"); | ||
| 113 | } | 137 | } |
| 114 | 138 | ||
| 115 | // Verify that Installation fails if FailIfExisits is set. | 139 | // Verify that Installation fails if FailIfExists is set. |
| 116 | [RuntimeFact] | 140 | [RuntimeFact] |
| 117 | public void FailsIfUserExists() | 141 | public void FailsIfUserExists() |
| 118 | { | 142 | { |
| @@ -135,7 +159,6 @@ namespace WixToolsetTest.MsiE2E | |||
| 135 | // clean up | 159 | // clean up |
| 136 | UserVerifier.DeleteLocalUser("existinguser"); | 160 | UserVerifier.DeleteLocalUser("existinguser"); |
| 137 | } | 161 | } |
| 138 | |||
| 139 | } | 162 | } |
| 140 | 163 | ||
| 141 | // Verify that a user cannot be created on a domain on which you dont have create user permission. | 164 | // Verify that a user cannot be created on a domain on which you dont have create user permission. |
| @@ -158,5 +181,98 @@ namespace WixToolsetTest.MsiE2E | |||
| 158 | 181 | ||
| 159 | productNonVitalGroup.InstallProduct(); | 182 | productNonVitalGroup.InstallProduct(); |
| 160 | } | 183 | } |
| 184 | |||
| 185 | // Verify that a user can be created with a user comment | ||
| 186 | [RuntimeFact] | ||
| 187 | public void CanCreateNewUserWithComment() | ||
| 188 | { | ||
| 189 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 190 | |||
| 191 | productNewUserWithComment.InstallProduct(); | ||
| 192 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 193 | |||
| 194 | // clean up | ||
| 195 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 196 | } | ||
| 197 | |||
| 198 | // Verify that a comment can be added to an existing user | ||
| 199 | [RuntimeFact] | ||
| 200 | public void CanAddCommentToExistingUser() | ||
| 201 | { | ||
| 202 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 203 | var productAddCommentToExistingUser = this.CreatePackageInstaller("ProductAddCommentToExistingUser"); | ||
| 204 | |||
| 205 | productAddCommentToExistingUser.InstallProduct(); | ||
| 206 | |||
| 207 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 208 | |||
| 209 | // clean up | ||
| 210 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 211 | } | ||
| 212 | |||
| 213 | // Verify that a comment can be repaired for a new user | ||
| 214 | [RuntimeFact] | ||
| 215 | public void CanRepairCommentOfNewUser() | ||
| 216 | { | ||
| 217 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 218 | |||
| 219 | productNewUserWithComment.InstallProduct(); | ||
| 220 | UserVerifier.SetUserComment(String.Empty, "testName1", ""); | ||
| 221 | |||
| 222 | productNewUserWithComment.RepairProduct(); | ||
| 223 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 224 | |||
| 225 | // clean up | ||
| 226 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 227 | } | ||
| 228 | |||
| 229 | // Verify that a comment can be changed for an existing user | ||
| 230 | [RuntimeFact] | ||
| 231 | public void CanChangeCommentOfExistingUser() | ||
| 232 | { | ||
| 233 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 234 | UserVerifier.SetUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 235 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewUserWithComment"); | ||
| 236 | |||
| 237 | productNewUserWithComment.InstallProduct(); | ||
| 238 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "testComment1"); | ||
| 239 | |||
| 240 | // clean up | ||
| 241 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 242 | } | ||
| 243 | |||
| 244 | // Verify that a comment can be rolled back for an existing user | ||
| 245 | [RuntimeFact] | ||
| 246 | public void CanRollbackCommentOfExistingUser() | ||
| 247 | { | ||
| 248 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 249 | UserVerifier.SetUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 250 | var productCommentFail = this.CreatePackageInstaller("ProductCommentFail"); | ||
| 251 | |||
| 252 | productCommentFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); | ||
| 253 | |||
| 254 | // Verify that comment change was rolled back. | ||
| 255 | UserVerifier.VerifyUserComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 256 | |||
| 257 | // clean up | ||
| 258 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 259 | } | ||
| 260 | |||
| 261 | // Verify that a comment can be deleted for an existing user | ||
| 262 | [RuntimeFact] | ||
| 263 | public void CanDeleteCommentOfExistingUser() | ||
| 264 | { | ||
| 265 | UserVerifier.CreateLocalUser("testName1", "test123!@#"); | ||
| 266 | UserVerifier.SetUserComment(String.Empty, "testName1", "testComment1"); | ||
| 267 | var productCommentDelete = this.CreatePackageInstaller("ProductCommentDelete"); | ||
| 268 | |||
| 269 | productCommentDelete.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 270 | |||
| 271 | // Verify that comment was removed. | ||
| 272 | UserVerifier.VerifyUserComment(String.Empty, "testName1", ""); | ||
| 273 | |||
| 274 | // clean up | ||
| 275 | UserVerifier.DeleteLocalUser("testName1"); | ||
| 276 | } | ||
| 161 | } | 277 | } |
| 162 | } | 278 | } |
