diff options
author | Ron Martin <cpuwzd@comcast.net> | 2022-08-29 18:38:07 -0400 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2022-10-21 19:08:08 -0700 |
commit | 08cdc6aa2b9dd0e273a3c3a22893616d26342a0e (patch) | |
tree | 1d0b9f7e21cec02abfda50b1a3c6d0c24308998b /src | |
parent | 40bd65379768f99ec28bffe2691ba43c78c9e9c4 (diff) | |
download | wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.gz wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.tar.bz2 wix-08cdc6aa2b9dd0e273a3c3a22893616d26342a0e.zip |
Support add, modify and remove comments on user accounts
Fixes 5371
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 | } |