diff options
Diffstat (limited to '')
60 files changed, 2848 insertions, 136 deletions
diff --git a/src/ext/Firewall/ca/CustomMsiErrors.h b/src/ext/Firewall/ca/CustomMsiErrors.h index f149fb31..6a7f4b3c 100644 --- a/src/ext/Firewall/ca/CustomMsiErrors.h +++ b/src/ext/Firewall/ca/CustomMsiErrors.h | |||
| @@ -87,6 +87,10 @@ | |||
| 87 | #define msierrUSRFailedUserCreateExists 26404 | 87 | #define msierrUSRFailedUserCreateExists 26404 |
| 88 | #define msierrUSRFailedGrantLogonAsService 26405 | 88 | #define msierrUSRFailedGrantLogonAsService 26405 |
| 89 | 89 | ||
| 90 | #define msierrGRPFailedGroupCreate 26421 | ||
| 91 | #define msierrGRPFailedGroupGroupAdd 26422 | ||
| 92 | #define msierrGRPFailedGroupCreateExists 26423 | ||
| 93 | |||
| 90 | #define msierrDependencyMissingDependencies 26451 | 94 | #define msierrDependencyMissingDependencies 26451 |
| 91 | #define msierrDependencyHasDependents 26452 | 95 | #define msierrDependencyHasDependents 26452 |
| 92 | 96 | ||
diff --git a/src/ext/Iis/ca/sca.h b/src/ext/Iis/ca/sca.h index 6921613b..b97e9a7e 100644 --- a/src/ext/Iis/ca/sca.h +++ b/src/ext/Iis/ca/sca.h | |||
| @@ -123,3 +123,15 @@ enum SCAU_ATTRIBUTES | |||
| 123 | SCAU_NON_VITAL = 0x00000400, | 123 | SCAU_NON_VITAL = 0x00000400, |
| 124 | SCAU_REMOVE_COMMENT = 0x00000800, | 124 | SCAU_REMOVE_COMMENT = 0x00000800, |
| 125 | }; | 125 | }; |
| 126 | |||
| 127 | // group creation attributes definitions | ||
| 128 | enum SCAG_ATTRIBUTES | ||
| 129 | { | ||
| 130 | SCAG_FAIL_IF_EXISTS = 0x00000001, | ||
| 131 | SCAG_UPDATE_IF_EXISTS = 0x00000002, | ||
| 132 | |||
| 133 | SCAG_DONT_REMOVE_ON_UNINSTALL = 0x00000004, | ||
| 134 | SCAG_DONT_CREATE_GROUP = 0x00000008, | ||
| 135 | SCAG_NON_VITAL = 0x00000010, | ||
| 136 | SCAG_REMOVE_COMMENT = 0x00000020, | ||
| 137 | }; | ||
diff --git a/src/ext/Util/ca/CustomMsiErrors.h b/src/ext/Util/ca/CustomMsiErrors.h index 3218b61b..ac0c549f 100644 --- a/src/ext/Util/ca/CustomMsiErrors.h +++ b/src/ext/Util/ca/CustomMsiErrors.h | |||
| @@ -29,4 +29,8 @@ | |||
| 29 | #define msierrUSRFailedUserCreateExists 26404 | 29 | #define msierrUSRFailedUserCreateExists 26404 |
| 30 | #define msierrUSRFailedGrantLogonAsService 26405 | 30 | #define msierrUSRFailedGrantLogonAsService 26405 |
| 31 | 31 | ||
| 32 | //Last available is 26450 \ No newline at end of file | 32 | #define msierrGRPFailedGroupCreate 26421 |
| 33 | #define msierrGRPFailedGroupGroupAdd 26422 | ||
| 34 | #define msierrGRPFailedGroupCreateExists 26423 | ||
| 35 | |||
| 36 | //Last available is 26450 | ||
diff --git a/src/ext/Util/ca/sca.h b/src/ext/Util/ca/sca.h index 84f5ffd9..0e25a19a 100644 --- a/src/ext/Util/ca/sca.h +++ b/src/ext/Util/ca/sca.h | |||
| @@ -18,3 +18,15 @@ enum SCAU_ATTRIBUTES | |||
| 18 | SCAU_NON_VITAL = 0x00000400, | 18 | SCAU_NON_VITAL = 0x00000400, |
| 19 | SCAU_REMOVE_COMMENT = 0x00000800, | 19 | SCAU_REMOVE_COMMENT = 0x00000800, |
| 20 | }; | 20 | }; |
| 21 | |||
| 22 | // group creation attributes definitions | ||
| 23 | enum SCAG_ATTRIBUTES | ||
| 24 | { | ||
| 25 | SCAG_FAIL_IF_EXISTS = 0x00000001, | ||
| 26 | SCAG_UPDATE_IF_EXISTS = 0x00000002, | ||
| 27 | |||
| 28 | SCAG_DONT_REMOVE_ON_UNINSTALL = 0x00000004, | ||
| 29 | SCAG_DONT_CREATE_GROUP = 0x00000008, | ||
| 30 | SCAG_NON_VITAL = 0x00000010, | ||
| 31 | SCAG_REMOVE_COMMENT = 0x00000020, | ||
| 32 | }; | ||
diff --git a/src/ext/Util/ca/scacost.h b/src/ext/Util/ca/scacost.h index 5b215035..978e40bc 100644 --- a/src/ext/Util/ca/scacost.h +++ b/src/ext/Util/ca/scacost.h | |||
| @@ -9,6 +9,8 @@ const UINT COST_SMB_CREATESMB = 10000; | |||
| 9 | const UINT COST_SMB_DROPSMB = 5000; | 9 | const UINT COST_SMB_DROPSMB = 5000; |
| 10 | const UINT COST_USER_ADD = 10000; | 10 | const UINT COST_USER_ADD = 10000; |
| 11 | const UINT COST_USER_DELETE = 10000; | 11 | const UINT COST_USER_DELETE = 10000; |
| 12 | const UINT COST_GROUP_ADD = 10000; | ||
| 13 | const UINT COST_GROUP_DELETE = 10000; | ||
| 12 | 14 | ||
| 13 | const UINT COST_PERFMONMANIFEST_REGISTER = 1000; | 15 | const UINT COST_PERFMONMANIFEST_REGISTER = 1000; |
| 14 | const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; | 16 | const UINT COST_PERFMONMANIFEST_UNREGISTER = 1000; |
diff --git a/src/ext/Util/ca/scaexec.cpp b/src/ext/Util/ca/scaexec.cpp index 8579b8bb..5a750c6b 100644 --- a/src/ext/Util/ca/scaexec.cpp +++ b/src/ext/Util/ca/scaexec.cpp | |||
| @@ -291,6 +291,145 @@ LExit: | |||
| 291 | return hr; | 291 | return hr; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | static HRESULT AddGroupToGroup( | ||
| 295 | __in LPWSTR wzMember, | ||
| 296 | __in LPCWSTR wzMemberDomain, | ||
| 297 | __in LPCWSTR wzGroup, | ||
| 298 | __in LPCWSTR wzGroupDomain | ||
| 299 | ) | ||
| 300 | { | ||
| 301 | Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); | ||
| 302 | |||
| 303 | HRESULT hr = S_OK; | ||
| 304 | IADsGroup* pGroup = NULL; | ||
| 305 | BSTR bstrMember = NULL; | ||
| 306 | BSTR bstrGroup = NULL; | ||
| 307 | LPWSTR pwzMember = NULL; | ||
| 308 | LPWSTR pwzServerName = NULL; | ||
| 309 | LOCALGROUP_MEMBERS_INFO_3 lgmi {}; | ||
| 310 | |||
| 311 | GetDomainServerName(wzGroupDomain, &pwzServerName); | ||
| 312 | |||
| 313 | // Try adding it to the local group | ||
| 314 | if (wzMemberDomain) | ||
| 315 | { | ||
| 316 | hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); | ||
| 317 | ExitOnFailure(hr, "failed to allocate group domain string"); | ||
| 318 | } | ||
| 319 | |||
| 320 | lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); | ||
| 321 | NET_API_STATUS ui = ::NetLocalGroupAddMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1); | ||
| 322 | hr = HRESULT_FROM_WIN32(ui); | ||
| 323 | if (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr) // if they're already a member of the group don't report an error | ||
| 324 | { | ||
| 325 | hr = S_OK; | ||
| 326 | } | ||
| 327 | |||
| 328 | // | ||
| 329 | // If we failed, try active directory | ||
| 330 | // | ||
| 331 | if (FAILED(hr)) | ||
| 332 | { | ||
| 333 | WcaLog(LOGMSG_VERBOSE, "Failed to add group: %ls, domain %ls to group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr); | ||
| 334 | |||
| 335 | hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); | ||
| 336 | ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzMember, wzMemberDomain); | ||
| 337 | |||
| 338 | hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); | ||
| 339 | ExitOnFailure(hr, "failed to create group ADsPath for group: %ls domain: %ls", wzGroup, wzGroupDomain); | ||
| 340 | |||
| 341 | hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup)); | ||
| 342 | ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup)); | ||
| 343 | |||
| 344 | hr = pGroup->Add(bstrMember); | ||
| 345 | if ((HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS) == hr) || (HRESULT_FROM_WIN32(ERROR_MEMBER_IN_ALIAS) == hr)) | ||
| 346 | hr = S_OK; | ||
| 347 | |||
| 348 | ExitOnFailure(hr, "Failed to add group %ls to group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup)); | ||
| 349 | } | ||
| 350 | |||
| 351 | LExit: | ||
| 352 | ReleaseStr(pwzServerName); | ||
| 353 | ReleaseStr(pwzMember); | ||
| 354 | ReleaseBSTR(bstrMember); | ||
| 355 | ReleaseBSTR(bstrGroup); | ||
| 356 | ReleaseObject(pGroup); | ||
| 357 | |||
| 358 | return hr; | ||
| 359 | } | ||
| 360 | |||
| 361 | static HRESULT RemoveGroupFromGroup( | ||
| 362 | __in LPWSTR wzMember, | ||
| 363 | __in LPCWSTR wzMemberDomain, | ||
| 364 | __in LPCWSTR wzGroup, | ||
| 365 | __in LPCWSTR wzGroupDomain | ||
| 366 | ) | ||
| 367 | { | ||
| 368 | Assert(wzMember && *wzMember && wzMemberDomain && wzGroup && *wzGroup && wzGroupDomain); | ||
| 369 | |||
| 370 | HRESULT hr = S_OK; | ||
| 371 | IADsGroup* pGroup = NULL; | ||
| 372 | BSTR bstrMember = NULL; | ||
| 373 | BSTR bstrGroup = NULL; | ||
| 374 | LPWSTR pwzMember = NULL; | ||
| 375 | LPWSTR pwzServerName = NULL; | ||
| 376 | LOCALGROUP_MEMBERS_INFO_3 lgmi {}; | ||
| 377 | |||
| 378 | GetDomainServerName(wzGroupDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
| 379 | |||
| 380 | // Try removing it from the local group | ||
| 381 | if (wzMemberDomain) | ||
| 382 | { | ||
| 383 | hr = StrAllocFormatted(&pwzMember, L"%s\\%s", wzMemberDomain, wzMember); | ||
| 384 | ExitOnFailure(hr, "failed to allocate group domain string"); | ||
| 385 | } | ||
| 386 | |||
| 387 | lgmi.lgrmi3_domainandname = (NULL == pwzMember ? wzMember : pwzMember); | ||
| 388 | NET_API_STATUS ui = ::NetLocalGroupDelMembers(pwzServerName, wzGroup, 3, reinterpret_cast<LPBYTE>(&lgmi), 1); | ||
| 389 | hr = HRESULT_FROM_WIN32(ui); | ||
| 390 | if (HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr | ||
| 391 | || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr | ||
| 392 | || HRESULT_FROM_WIN32(ERROR_NO_SUCH_MEMBER) == hr) // if they're already not a member of the group, or the group doesn't exist, don't report an error | ||
| 393 | { | ||
| 394 | hr = S_OK; | ||
| 395 | } | ||
| 396 | |||
| 397 | // | ||
| 398 | // If we failed, try active directory | ||
| 399 | // | ||
| 400 | if (FAILED(hr)) | ||
| 401 | { | ||
| 402 | WcaLog(LOGMSG_VERBOSE, "Failed to remove group: %ls, domain %ls from group: %ls, domain: %ls with error 0x%x. Attempting to use Active Directory", wzMember, wzMemberDomain, wzGroup, wzGroupDomain, hr); | ||
| 403 | |||
| 404 | hr = UserCreateADsPath(wzMemberDomain, wzMember, &bstrMember); | ||
| 405 | ExitOnFailure(hr, "failed to create group ADsPath in order to remove group: %ls domain: %ls from a group", wzMember, wzMemberDomain); | ||
| 406 | |||
| 407 | hr = UserCreateADsPath(wzGroupDomain, wzGroup, &bstrGroup); | ||
| 408 | ExitOnFailure(hr, "failed to create group ADsPath in order to remove group from group: %ls domain: %ls", wzGroup, wzGroupDomain); | ||
| 409 | |||
| 410 | hr = ::ADsGetObject(bstrGroup, IID_IADsGroup, reinterpret_cast<void**>(&pGroup)); | ||
| 411 | if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)) // if parent group not found, no need to remove membership from group | ||
| 412 | { | ||
| 413 | hr = S_OK; | ||
| 414 | ExitFunction(); | ||
| 415 | } | ||
| 416 | ExitOnFailure(hr, "Failed to get group '%ls'.", reinterpret_cast<WCHAR*>(bstrGroup)); | ||
| 417 | |||
| 418 | hr = pGroup->Remove(bstrMember); | ||
| 419 | if ((HRESULT_FROM_WIN32(ERROR_MEMBER_NOT_IN_ALIAS) == hr)) // if already not a member, no need to worry about error | ||
| 420 | hr = S_OK; | ||
| 421 | ExitOnFailure(hr, "Failed to remove group %ls from group '%ls'.", reinterpret_cast<WCHAR*>(bstrMember), reinterpret_cast<WCHAR*>(bstrGroup)); | ||
| 422 | } | ||
| 423 | |||
| 424 | LExit: | ||
| 425 | ReleaseStr(pwzServerName); | ||
| 426 | ReleaseStr(pwzMember); | ||
| 427 | ReleaseBSTR(bstrMember); | ||
| 428 | ReleaseBSTR(bstrGroup); | ||
| 429 | ReleaseObject(pGroup); | ||
| 430 | |||
| 431 | return hr; | ||
| 432 | } | ||
| 294 | 433 | ||
| 295 | static HRESULT GetUserHasRight( | 434 | static HRESULT GetUserHasRight( |
| 296 | __in LSA_HANDLE hPolicy, | 435 | __in LSA_HANDLE hPolicy, |
| @@ -590,6 +729,15 @@ static HRESULT SetUserComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __ | |||
| 590 | return HRESULT_FROM_WIN32(er); | 729 | return HRESULT_FROM_WIN32(er); |
| 591 | } | 730 | } |
| 592 | 731 | ||
| 732 | static HRESULT SetGroupComment(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in LPWSTR pwzComment) | ||
| 733 | { | ||
| 734 | _LOCALGROUP_INFO_1002 groupInfo1002 {}; | ||
| 735 | |||
| 736 | groupInfo1002.lgrpi1002_comment = pwzComment; | ||
| 737 | NET_API_STATUS er = ::NetLocalGroupSetInfo(pwzServerName, pwzName, 1002, reinterpret_cast<LPBYTE>(&groupInfo1002), NULL); | ||
| 738 | return HRESULT_FROM_WIN32(er); | ||
| 739 | } | ||
| 740 | |||
| 593 | static HRESULT SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) | 741 | static HRESULT SetUserFlags(__in LPWSTR pwzServerName, __in LPWSTR pwzName, __in DWORD flags) |
| 594 | { | 742 | { |
| 595 | NET_API_STATUS er = NERR_Success; | 743 | NET_API_STATUS er = NERR_Success; |
| @@ -693,6 +841,76 @@ LExit: | |||
| 693 | return hr; | 841 | return hr; |
| 694 | } | 842 | } |
| 695 | 843 | ||
| 844 | static HRESULT RemoveGroupInternal( | ||
| 845 | LPWSTR wzGroupCaData, | ||
| 846 | LPWSTR wzDomain, | ||
| 847 | LPWSTR wzName, | ||
| 848 | int iAttributes | ||
| 849 | ) | ||
| 850 | { | ||
| 851 | HRESULT hr = S_OK; | ||
| 852 | |||
| 853 | LPWSTR pwz = NULL; | ||
| 854 | LPWSTR pwzGroup = NULL; | ||
| 855 | LPWSTR pwzGroupDomain = NULL; | ||
| 856 | LPWSTR pwzServerName = NULL; | ||
| 857 | |||
| 858 | // | ||
| 859 | // Remove the Group if the group was created by us. | ||
| 860 | // | ||
| 861 | if (!(SCAG_DONT_CREATE_GROUP & iAttributes)) | ||
| 862 | { | ||
| 863 | GetDomainServerName(wzDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
| 864 | |||
| 865 | NET_API_STATUS er = ::NetLocalGroupDel(pwzServerName, wzName); | ||
| 866 | hr = HRESULT_FROM_WIN32(er); | ||
| 867 | if (HRESULT_FROM_WIN32(ERROR_NO_SUCH_ALIAS) == hr | ||
| 868 | || HRESULT_FROM_WIN32(NERR_GroupNotFound) == hr) // we wanted to delete it.. and the group doesn't exist.. solved. | ||
| 869 | { | ||
| 870 | hr = S_OK; | ||
| 871 | } | ||
| 872 | ExitOnFailure(hr, "failed to delete group: %ls", wzName); | ||
| 873 | } | ||
| 874 | else | ||
| 875 | { | ||
| 876 | // | ||
| 877 | // Remove the group from other groups | ||
| 878 | // | ||
| 879 | pwz = wzGroupCaData; | ||
| 880 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
| 881 | { | ||
| 882 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
| 883 | |||
| 884 | if (FAILED(hr)) | ||
| 885 | { | ||
| 886 | WcaLogError(hr, "failed to get domain for group: %ls, continuing anyway.", pwzGroup); | ||
| 887 | } | ||
| 888 | else | ||
| 889 | { | ||
| 890 | hr = RemoveGroupFromGroup(wzName, wzDomain, pwzGroup, pwzGroupDomain); | ||
| 891 | if (FAILED(hr)) | ||
| 892 | { | ||
| 893 | WcaLogError(hr, "failed to remove group: %ls from group %ls, continuing anyway.", wzName, pwzGroup); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | } | ||
| 897 | |||
| 898 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | ||
| 899 | { | ||
| 900 | hr = S_OK; | ||
| 901 | } | ||
| 902 | |||
| 903 | ExitOnFailure(hr, "failed to get next group from which to remove group:%ls", wzName); | ||
| 904 | } | ||
| 905 | LExit: | ||
| 906 | ReleaseStr(pwzServerName); | ||
| 907 | ReleaseStr(pwzGroup); | ||
| 908 | ReleaseStr(pwzGroupDomain); | ||
| 909 | |||
| 910 | return hr; | ||
| 911 | } | ||
| 912 | |||
| 913 | |||
| 696 | /******************************************************************** | 914 | /******************************************************************** |
| 697 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users | 915 | CreateUser - CUSTOM ACTION ENTRY POINT for creating users |
| 698 | 916 | ||
| @@ -1173,3 +1391,413 @@ LExit: | |||
| 1173 | 1391 | ||
| 1174 | return WcaFinalize(er); | 1392 | return WcaFinalize(er); |
| 1175 | } | 1393 | } |
| 1394 | |||
| 1395 | /******************************************************************** | ||
| 1396 | CreateGroup - CUSTOM ACTION ENTRY POINT for creating groups | ||
| 1397 | |||
| 1398 | Input: deferred CustomActionData - GroupName\tDomain\tComment\tAttributes | ||
| 1399 | * *****************************************************************/ | ||
| 1400 | extern "C" UINT __stdcall CreateGroup( | ||
| 1401 | __in MSIHANDLE hInstall | ||
| 1402 | ) | ||
| 1403 | { | ||
| 1404 | //AssertSz(0, "Debug CreateGroup"); | ||
| 1405 | |||
| 1406 | HRESULT hr = S_OK; | ||
| 1407 | NET_API_STATUS er = ERROR_SUCCESS; | ||
| 1408 | |||
| 1409 | LPWSTR pwzData = NULL; | ||
| 1410 | LPWSTR pwz = NULL; | ||
| 1411 | LPWSTR pwzName = NULL; | ||
| 1412 | LPWSTR pwzDomain = NULL; | ||
| 1413 | LPWSTR pwzComment = NULL; | ||
| 1414 | LPWSTR pwzScriptKey = NULL; | ||
| 1415 | LPWSTR pwzGroup = NULL; | ||
| 1416 | LPWSTR pwzGroupDomain = NULL; | ||
| 1417 | int iAttributes = 0; | ||
| 1418 | BOOL fInitializedCom = FALSE; | ||
| 1419 | |||
| 1420 | LOCALGROUP_INFO_1* pGroupInfo1 = NULL; | ||
| 1421 | |||
| 1422 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | ||
| 1423 | int iRollbackAttributes = 0; | ||
| 1424 | |||
| 1425 | DWORD dw; | ||
| 1426 | LPWSTR pwzServerName = NULL; | ||
| 1427 | |||
| 1428 | hr = WcaInitialize(hInstall, "CreateGroup"); | ||
| 1429 | ExitOnFailure(hr, "failed to initialize"); | ||
| 1430 | |||
| 1431 | hr = ::CoInitialize(NULL); | ||
| 1432 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 1433 | fInitializedCom = TRUE; | ||
| 1434 | |||
| 1435 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 1436 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1437 | |||
| 1438 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 1439 | |||
| 1440 | // | ||
| 1441 | // Read in the CustomActionData | ||
| 1442 | // | ||
| 1443 | pwz = pwzData; | ||
| 1444 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
| 1445 | ExitOnFailure(hr, "failed to read group name from custom action data"); | ||
| 1446 | |||
| 1447 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
| 1448 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
| 1449 | |||
| 1450 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1451 | ExitOnFailure(hr, "failed to read group comment from custom action data"); | ||
| 1452 | |||
| 1453 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 1454 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
| 1455 | |||
| 1456 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
| 1457 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
| 1458 | |||
| 1459 | if (!(SCAG_DONT_CREATE_GROUP & iAttributes)) | ||
| 1460 | { | ||
| 1461 | hr = GetDomainServerName(pwzDomain, &pwzServerName, DS_WRITABLE_REQUIRED); | ||
| 1462 | ExitOnFailure(hr, "failed to find Domain %ls.", pwzDomain); | ||
| 1463 | |||
| 1464 | // Set the group's comment | ||
| 1465 | if (SCAG_REMOVE_COMMENT & iAttributes) | ||
| 1466 | { | ||
| 1467 | StrAllocString(&pwzComment, L"", 0); | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | // | ||
| 1471 | // Create the Group | ||
| 1472 | // | ||
| 1473 | LOCALGROUP_INFO_1 groupInfo1; | ||
| 1474 | groupInfo1.lgrpi1_name = pwzName; | ||
| 1475 | groupInfo1.lgrpi1_comment = pwzComment; | ||
| 1476 | er = ::NetLocalGroupAdd(pwzServerName, 1, reinterpret_cast<LPBYTE>(&groupInfo1), &dw); | ||
| 1477 | hr = HRESULT_FROM_WIN32(er); | ||
| 1478 | |||
| 1479 | if (HRESULT_FROM_WIN32(ERROR_ALIAS_EXISTS) == hr | ||
| 1480 | || HRESULT_FROM_WIN32(NERR_GroupExists) == hr) | ||
| 1481 | { | ||
| 1482 | if (SCAG_FAIL_IF_EXISTS & iAttributes) | ||
| 1483 | { | ||
| 1484 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Group (%ls) was not supposed to exist, but does", pwzName); | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | hr = S_OK; // Make sure that we don't report this situation as an error | ||
| 1488 | // if we fall through the tests that follow. | ||
| 1489 | |||
| 1490 | if (SCAG_UPDATE_IF_EXISTS & iAttributes) | ||
| 1491 | { | ||
| 1492 | er = ::NetLocalGroupGetInfo(pwzServerName, pwzName, 1, reinterpret_cast<LPBYTE*>(&pGroupInfo1)); | ||
| 1493 | hr = HRESULT_FROM_WIN32(er); | ||
| 1494 | if (S_OK == hr) | ||
| 1495 | { | ||
| 1496 | // There is no rollback scheduled if the key is empty. | ||
| 1497 | // Best effort to get original configuration and save it in the script so rollback can restore it. | ||
| 1498 | if (*pwzScriptKey) | ||
| 1499 | { | ||
| 1500 | // Try to open the rollback script | ||
| 1501 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
| 1502 | |||
| 1503 | if (hRollbackScript && INVALID_HANDLE_VALUE != hRollbackScript->hScriptFile) | ||
| 1504 | { | ||
| 1505 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 1506 | } | ||
| 1507 | else | ||
| 1508 | { | ||
| 1509 | hRollbackScript = NULL; | ||
| 1510 | hr = WcaCaScriptCreate(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, FALSE, &hRollbackScript); | ||
| 1511 | ExitOnFailure(hr, "Failed to open rollback CustomAction script."); | ||
| 1512 | |||
| 1513 | iRollbackAttributes = 0; | ||
| 1514 | |||
| 1515 | hr = WcaCaScriptWriteString(hRollbackScript, pGroupInfo1->lgrpi1_comment); | ||
| 1516 | ExitOnFailure(hr, "Failed to add rollback comment to rollback script."); | ||
| 1517 | |||
| 1518 | if (!pGroupInfo1->lgrpi1_comment || !*pGroupInfo1->lgrpi1_comment) | ||
| 1519 | { | ||
| 1520 | iRollbackAttributes |= SCAG_REMOVE_COMMENT; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | hr = WcaCaScriptWriteNumber(hRollbackScript, iRollbackAttributes); | ||
| 1524 | ExitOnFailure(hr, "Failed to add rollback attributes to rollback script."); | ||
| 1525 | |||
| 1526 | // Nudge the system to get all our rollback data written to disk. | ||
| 1527 | WcaCaScriptFlush(hRollbackScript); | ||
| 1528 | } | ||
| 1529 | } | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | if (S_OK == hr) | ||
| 1533 | { | ||
| 1534 | if (SCAG_REMOVE_COMMENT & iAttributes) | ||
| 1535 | { | ||
| 1536 | hr = SetGroupComment(pwzServerName, pwzName, L""); | ||
| 1537 | if (FAILED(hr)) | ||
| 1538 | { | ||
| 1539 | WcaLogError(hr, "failed to clear comment for group %ls\\%ls, continuing anyway.", pwzServerName, pwzName); | ||
| 1540 | hr = S_OK; | ||
| 1541 | } | ||
| 1542 | } | ||
| 1543 | else if (pwzComment && *pwzComment) | ||
| 1544 | { | ||
| 1545 | hr = SetGroupComment(pwzServerName, pwzName, pwzComment); | ||
| 1546 | if (FAILED(hr)) | ||
| 1547 | { | ||
| 1548 | WcaLogError(hr, "failed to set comment to %ls for group %ls\\%ls, continuing anyway.", pwzComment, pwzServerName, pwzName); | ||
| 1549 | hr = S_OK; | ||
| 1550 | } | ||
| 1551 | } | ||
| 1552 | } | ||
| 1553 | } | ||
| 1554 | } | ||
| 1555 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreate, "failed to create group: %ls", pwzName); | ||
| 1556 | |||
| 1557 | // | ||
| 1558 | // Add the groups to groups | ||
| 1559 | // | ||
| 1560 | while (S_OK == (hr = WcaReadStringFromCaData(&pwz, &pwzGroup))) | ||
| 1561 | { | ||
| 1562 | hr = WcaReadStringFromCaData(&pwz, &pwzGroupDomain); | ||
| 1563 | ExitOnFailure(hr, "failed to get domain for group: %ls", pwzGroup); | ||
| 1564 | |||
| 1565 | WcaLog(LOGMSG_STANDARD, "Adding group %ls\\%ls to group %ls\\%ls", pwzDomain, pwzName, pwzGroupDomain, pwzGroup); | ||
| 1566 | hr = AddGroupToGroup(pwzName, pwzDomain, pwzGroup, pwzGroupDomain); | ||
| 1567 | MessageExitOnFailure(hr, msierrUSRFailedUserGroupAdd, "failed to add group: %ls to group %ls", pwzName, pwzGroup); | ||
| 1568 | } | ||
| 1569 | if (E_NOMOREITEMS == hr) // if there are no more items, all is well | ||
| 1570 | { | ||
| 1571 | hr = S_OK; | ||
| 1572 | } | ||
| 1573 | ExitOnFailure(hr, "failed to get next group in which to include group: %ls", pwzName); | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | LExit: | ||
| 1577 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_PRESERVE); | ||
| 1578 | |||
| 1579 | if (pGroupInfo1) | ||
| 1580 | { | ||
| 1581 | ::NetApiBufferFree((LPVOID)pGroupInfo1); | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | ReleaseStr(pwzData); | ||
| 1585 | ReleaseStr(pwzName); | ||
| 1586 | ReleaseStr(pwzDomain); | ||
| 1587 | ReleaseStr(pwzComment); | ||
| 1588 | ReleaseStr(pwzScriptKey); | ||
| 1589 | ReleaseStr(pwzGroup); | ||
| 1590 | ReleaseStr(pwzGroupDomain); | ||
| 1591 | |||
| 1592 | if (fInitializedCom) | ||
| 1593 | { | ||
| 1594 | ::CoUninitialize(); | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | if (SCAG_NON_VITAL & iAttributes) | ||
| 1598 | { | ||
| 1599 | er = ERROR_SUCCESS; | ||
| 1600 | } | ||
| 1601 | else if (FAILED(hr)) | ||
| 1602 | { | ||
| 1603 | er = ERROR_INSTALL_FAILURE; | ||
| 1604 | } | ||
| 1605 | |||
| 1606 | return WcaFinalize(er); | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | |||
| 1610 | /******************************************************************** | ||
| 1611 | CreateGroupRollback - CUSTOM ACTION ENTRY POINT for CreateGroup rollback | ||
| 1612 | |||
| 1613 | * *****************************************************************/ | ||
| 1614 | extern "C" UINT __stdcall CreateGroupRollback( | ||
| 1615 | MSIHANDLE hInstall | ||
| 1616 | ) | ||
| 1617 | { | ||
| 1618 | //AssertSz(0, "Debug CreateGroupRollback"); | ||
| 1619 | |||
| 1620 | HRESULT hr = S_OK; | ||
| 1621 | UINT er = ERROR_SUCCESS; | ||
| 1622 | |||
| 1623 | LPWSTR pwzData = NULL; | ||
| 1624 | LPWSTR pwz = NULL; | ||
| 1625 | LPWSTR pwzScriptKey = NULL; | ||
| 1626 | LPWSTR pwzName = NULL; | ||
| 1627 | LPWSTR pwzDomain = NULL; | ||
| 1628 | LPWSTR pwzComment = NULL; | ||
| 1629 | int iAttributes = 0; | ||
| 1630 | BOOL fInitializedCom = FALSE; | ||
| 1631 | |||
| 1632 | WCA_CASCRIPT_HANDLE hRollbackScript = NULL; | ||
| 1633 | LPWSTR pwzRollbackData = NULL; | ||
| 1634 | int iOriginalAttributes = 0; | ||
| 1635 | LPWSTR pwzOriginalComment = NULL; | ||
| 1636 | |||
| 1637 | hr = WcaInitialize(hInstall, "CreateGroupRollback"); | ||
| 1638 | ExitOnFailure(hr, "failed to initialize"); | ||
| 1639 | |||
| 1640 | hr = ::CoInitialize(NULL); | ||
| 1641 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 1642 | fInitializedCom = TRUE; | ||
| 1643 | |||
| 1644 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 1645 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1646 | |||
| 1647 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 1648 | |||
| 1649 | // | ||
| 1650 | // Read in the CustomActionData | ||
| 1651 | // | ||
| 1652 | pwz = pwzData; | ||
| 1653 | hr = WcaReadStringFromCaData(&pwz, &pwzScriptKey); | ||
| 1654 | ExitOnFailure(hr, "failed to read encoding key from custom action data"); | ||
| 1655 | |||
| 1656 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
| 1657 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
| 1658 | |||
| 1659 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
| 1660 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
| 1661 | |||
| 1662 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1663 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1664 | |||
| 1665 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 1666 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
| 1667 | |||
| 1668 | // Best effort to read original configuration from CreateUser. | ||
| 1669 | hr = WcaCaScriptOpen(WCA_ACTION_INSTALL, WCA_CASCRIPT_ROLLBACK, FALSE, pwzScriptKey, &hRollbackScript); | ||
| 1670 | if (FAILED(hr)) | ||
| 1671 | { | ||
| 1672 | WcaLogError(hr, "Failed to open rollback CustomAction script, continuing anyway."); | ||
| 1673 | } | ||
| 1674 | else | ||
| 1675 | { | ||
| 1676 | hr = WcaCaScriptReadAsCustomActionData(hRollbackScript, &pwzRollbackData); | ||
| 1677 | if (FAILED(hr)) | ||
| 1678 | { | ||
| 1679 | WcaLogError(hr, "Failed to read rollback script into CustomAction data, continuing anyway."); | ||
| 1680 | } | ||
| 1681 | else | ||
| 1682 | { | ||
| 1683 | WcaLog(LOGMSG_TRACEONLY, "Rollback Data: %ls", pwzRollbackData); | ||
| 1684 | |||
| 1685 | pwz = pwzRollbackData; | ||
| 1686 | hr = WcaReadStringFromCaData(&pwz, &pwzOriginalComment); | ||
| 1687 | if (FAILED(hr)) | ||
| 1688 | { | ||
| 1689 | WcaLogError(hr, "failed to read comment from rollback data, continuing anyway"); | ||
| 1690 | } | ||
| 1691 | else | ||
| 1692 | { | ||
| 1693 | pwzComment = pwzOriginalComment; | ||
| 1694 | } | ||
| 1695 | hr = WcaReadIntegerFromCaData(&pwz, &iOriginalAttributes); | ||
| 1696 | if (FAILED(hr)) | ||
| 1697 | { | ||
| 1698 | WcaLogError(hr, "failed to read attributes from rollback data, continuing anyway"); | ||
| 1699 | } | ||
| 1700 | else | ||
| 1701 | { | ||
| 1702 | iAttributes |= iOriginalAttributes; | ||
| 1703 | } | ||
| 1704 | } | ||
| 1705 | } | ||
| 1706 | |||
| 1707 | hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); | ||
| 1708 | |||
| 1709 | LExit: | ||
| 1710 | WcaCaScriptClose(hRollbackScript, WCA_CASCRIPT_CLOSE_DELETE); | ||
| 1711 | |||
| 1712 | ReleaseStr(pwzData); | ||
| 1713 | ReleaseStr(pwzName); | ||
| 1714 | ReleaseStr(pwzDomain); | ||
| 1715 | ReleaseStr(pwzComment); | ||
| 1716 | ReleaseStr(pwzScriptKey); | ||
| 1717 | ReleaseStr(pwzRollbackData); | ||
| 1718 | ReleaseStr(pwzOriginalComment); | ||
| 1719 | |||
| 1720 | if (fInitializedCom) | ||
| 1721 | { | ||
| 1722 | ::CoUninitialize(); | ||
| 1723 | } | ||
| 1724 | |||
| 1725 | if (FAILED(hr)) | ||
| 1726 | { | ||
| 1727 | er = ERROR_INSTALL_FAILURE; | ||
| 1728 | } | ||
| 1729 | |||
| 1730 | return WcaFinalize(er); | ||
| 1731 | } | ||
| 1732 | |||
| 1733 | |||
| 1734 | /******************************************************************** | ||
| 1735 | RemoveGroup - CUSTOM ACTION ENTRY POINT for removing groups | ||
| 1736 | |||
| 1737 | Input: deferred CustomActionData - Name\tDomain | ||
| 1738 | * *****************************************************************/ | ||
| 1739 | extern "C" UINT __stdcall RemoveGroup( | ||
| 1740 | MSIHANDLE hInstall | ||
| 1741 | ) | ||
| 1742 | { | ||
| 1743 | //AssertSz(0, "Debug RemoveGroup"); | ||
| 1744 | |||
| 1745 | HRESULT hr = S_OK; | ||
| 1746 | UINT er = ERROR_SUCCESS; | ||
| 1747 | |||
| 1748 | LPWSTR pwzData = NULL; | ||
| 1749 | LPWSTR pwz = NULL; | ||
| 1750 | LPWSTR pwzName = NULL; | ||
| 1751 | LPWSTR pwzDomain = NULL; | ||
| 1752 | LPWSTR pwzComment = NULL; | ||
| 1753 | int iAttributes = 0; | ||
| 1754 | BOOL fInitializedCom = FALSE; | ||
| 1755 | |||
| 1756 | hr = WcaInitialize(hInstall, "RemoveGroup"); | ||
| 1757 | ExitOnFailure(hr, "failed to initialize"); | ||
| 1758 | |||
| 1759 | hr = ::CoInitialize(NULL); | ||
| 1760 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 1761 | fInitializedCom = TRUE; | ||
| 1762 | |||
| 1763 | hr = WcaGetProperty(L"CustomActionData", &pwzData); | ||
| 1764 | ExitOnFailure(hr, "failed to get CustomActionData"); | ||
| 1765 | |||
| 1766 | WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzData); | ||
| 1767 | |||
| 1768 | // | ||
| 1769 | // Read in the CustomActionData | ||
| 1770 | // | ||
| 1771 | pwz = pwzData; | ||
| 1772 | hr = WcaReadStringFromCaData(&pwz, &pwzName); | ||
| 1773 | ExitOnFailure(hr, "failed to read name from custom action data"); | ||
| 1774 | |||
| 1775 | hr = WcaReadStringFromCaData(&pwz, &pwzDomain); | ||
| 1776 | ExitOnFailure(hr, "failed to read domain from custom action data"); | ||
| 1777 | |||
| 1778 | hr = WcaReadStringFromCaData(&pwz, &pwzComment); | ||
| 1779 | ExitOnFailure(hr, "failed to read comment from custom action data"); | ||
| 1780 | |||
| 1781 | hr = WcaReadIntegerFromCaData(&pwz, &iAttributes); | ||
| 1782 | ExitOnFailure(hr, "failed to read attributes from custom action data"); | ||
| 1783 | |||
| 1784 | hr = RemoveGroupInternal(pwz, pwzDomain, pwzName, iAttributes); | ||
| 1785 | |||
| 1786 | LExit: | ||
| 1787 | ReleaseStr(pwzData); | ||
| 1788 | ReleaseStr(pwzName); | ||
| 1789 | ReleaseStr(pwzDomain); | ||
| 1790 | ReleaseStr(pwzComment); | ||
| 1791 | |||
| 1792 | if (fInitializedCom) | ||
| 1793 | { | ||
| 1794 | ::CoUninitialize(); | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | if (FAILED(hr)) | ||
| 1798 | { | ||
| 1799 | er = ERROR_INSTALL_FAILURE; | ||
| 1800 | } | ||
| 1801 | |||
| 1802 | return WcaFinalize(er); | ||
| 1803 | } | ||
diff --git a/src/ext/Util/ca/scagroup.cpp b/src/ext/Util/ca/scagroup.cpp new file mode 100644 index 00000000..c484c1d2 --- /dev/null +++ b/src/ext/Util/ca/scagroup.cpp | |||
| @@ -0,0 +1,503 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | #include "scanet.h" | ||
| 5 | |||
| 6 | LPCWSTR vcsGroupQuery = L"SELECT `Group`, `Component_`, `Name`, `Domain` FROM `Wix4Group` WHERE `Group`=?"; | ||
| 7 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
| 8 | |||
| 9 | LPCWSTR vcsGroupGroupQuery = L"SELECT `Parent_`, `Child_` FROM `Wix6GroupGroup` WHERE `Child_`=?"; | ||
| 10 | enum eGroupGroupQuery { vggqParent = 1, vggqChild }; | ||
| 11 | |||
| 12 | LPCWSTR vActionableGroupQuery = L"SELECT `Group`,`Component_`,`Name`,`Domain`,`Comment`,`Attributes` FROM `Wix4Group`,`Wix6Group` WHERE `Component_` IS NOT NULL AND `Group`=`Group_`"; | ||
| 13 | enum eActionableGroupQuery { vagqGroup = 1, vagqComponent, vagqName, vagqDomain, vagqComment, vagqAttributes }; | ||
| 14 | |||
| 15 | static HRESULT AddGroupToList( | ||
| 16 | __inout SCA_GROUP** ppsgList | ||
| 17 | ); | ||
| 18 | |||
| 19 | |||
| 20 | HRESULT __stdcall ScaGetGroup( | ||
| 21 | __in LPCWSTR wzGroup, | ||
| 22 | __out SCA_GROUP* pscag | ||
| 23 | ) | ||
| 24 | { | ||
| 25 | if (!wzGroup || *wzGroup==0 || !pscag) | ||
| 26 | { | ||
| 27 | return E_INVALIDARG; | ||
| 28 | } | ||
| 29 | |||
| 30 | HRESULT hr = S_OK; | ||
| 31 | PMSIHANDLE hView, hRec; | ||
| 32 | |||
| 33 | LPWSTR pwzData = NULL; | ||
| 34 | |||
| 35 | hRec = ::MsiCreateRecord(1); | ||
| 36 | hr = WcaSetRecordString(hRec, 1, wzGroup); | ||
| 37 | ExitOnFailure(hr, "Failed to look up Group"); | ||
| 38 | |||
| 39 | hr = WcaOpenView(vcsGroupQuery, &hView); | ||
| 40 | ExitOnFailure(hr, "Failed to open view on Wix4Group table"); | ||
| 41 | hr = WcaExecuteView(hView, hRec); | ||
| 42 | ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); | ||
| 43 | |||
| 44 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
| 45 | if (S_OK == hr) | ||
| 46 | { | ||
| 47 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
| 48 | ExitOnFailure(hr, "Failed to get Wix4Group.Group"); | ||
| 49 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
| 50 | ExitOnFailure(hr, "Failed to copy key string to group object"); | ||
| 51 | |||
| 52 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
| 53 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
| 54 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
| 55 | ExitOnFailure(hr, "Failed to copy component string to group object"); | ||
| 56 | |||
| 57 | hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); | ||
| 58 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
| 59 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
| 60 | ExitOnFailure(hr, "Failed to copy name string to group object"); | ||
| 61 | |||
| 62 | hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); | ||
| 63 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
| 64 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
| 65 | ExitOnFailure(hr, "Failed to copy domain string to group object"); | ||
| 66 | } | ||
| 67 | else if (E_NOMOREITEMS == hr) | ||
| 68 | { | ||
| 69 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
| 70 | hr = E_FAIL; | ||
| 71 | } | ||
| 72 | else | ||
| 73 | { | ||
| 74 | ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); | ||
| 75 | } | ||
| 76 | |||
| 77 | LExit: | ||
| 78 | ReleaseStr(pwzData); | ||
| 79 | |||
| 80 | return hr; | ||
| 81 | } | ||
| 82 | |||
| 83 | HRESULT __stdcall ScaGetGroupDeferred( | ||
| 84 | __in LPCWSTR wzGroup, | ||
| 85 | __in WCA_WRAPQUERY_HANDLE hGroupQuery, | ||
| 86 | __out SCA_USER* pscag | ||
| 87 | ) | ||
| 88 | { | ||
| 89 | if (!wzGroup || !pscag) | ||
| 90 | { | ||
| 91 | return E_INVALIDARG; | ||
| 92 | } | ||
| 93 | |||
| 94 | HRESULT hr = S_OK; | ||
| 95 | MSIHANDLE hRec, hRecTest; | ||
| 96 | |||
| 97 | LPWSTR pwzData = NULL; | ||
| 98 | |||
| 99 | // clear struct and bail right away if no group key was passed to search for | ||
| 100 | ::ZeroMemory(pscag, sizeof(*pscag)); | ||
| 101 | if (!*wzGroup) | ||
| 102 | { | ||
| 103 | ExitFunction1(hr = S_OK); | ||
| 104 | } | ||
| 105 | |||
| 106 | // Reset back to the first record | ||
| 107 | WcaFetchWrappedReset(hGroupQuery); | ||
| 108 | |||
| 109 | hr = WcaFetchWrappedRecordWhereString(hGroupQuery, vgqGroup, wzGroup, &hRec); | ||
| 110 | if (S_OK == hr) | ||
| 111 | { | ||
| 112 | hr = WcaFetchWrappedRecordWhereString(hGroupQuery, vgqGroup, wzGroup, &hRecTest); | ||
| 113 | if (S_OK == hr) | ||
| 114 | { | ||
| 115 | AssertSz(FALSE, "Found multiple matching Wix4Group rows"); | ||
| 116 | } | ||
| 117 | |||
| 118 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
| 119 | ExitOnFailure(hr, "Failed to get Wix4Group.Group"); | ||
| 120 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
| 121 | ExitOnFailure(hr, "Failed to copy key string to group object (in deferred CA)"); | ||
| 122 | |||
| 123 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
| 124 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
| 125 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
| 126 | ExitOnFailure(hr, "Failed to copy component string to group object (in deferred CA)"); | ||
| 127 | |||
| 128 | hr = WcaGetRecordString(hRec, vgqName, &pwzData); | ||
| 129 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
| 130 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
| 131 | ExitOnFailure(hr, "Failed to copy name string to group object (in deferred CA)"); | ||
| 132 | |||
| 133 | hr = WcaGetRecordString(hRec, vgqDomain, &pwzData); | ||
| 134 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
| 135 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
| 136 | ExitOnFailure(hr, "Failed to copy domain string to group object (in deferred CA)"); | ||
| 137 | } | ||
| 138 | else if (E_NOMOREITEMS == hr) | ||
| 139 | { | ||
| 140 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
| 141 | hr = E_FAIL; | ||
| 142 | } | ||
| 143 | else | ||
| 144 | { | ||
| 145 | ExitOnFailure(hr, "Error fetching single Wix4Group row"); | ||
| 146 | } | ||
| 147 | |||
| 148 | LExit: | ||
| 149 | ReleaseStr(pwzData); | ||
| 150 | |||
| 151 | return hr; | ||
| 152 | } | ||
| 153 | |||
| 154 | void ScaGroupFreeList( | ||
| 155 | __in SCA_GROUP* psgList | ||
| 156 | ) | ||
| 157 | { | ||
| 158 | SCA_GROUP* psgDelete = psgList; | ||
| 159 | while (psgList) | ||
| 160 | { | ||
| 161 | psgDelete = psgList; | ||
| 162 | psgList = psgList->psgNext; | ||
| 163 | |||
| 164 | MemFree(psgDelete); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | |||
| 169 | HRESULT ScaGroupRead( | ||
| 170 | __out SCA_GROUP** ppsgList | ||
| 171 | ) | ||
| 172 | { | ||
| 173 | //Assert(FALSE); | ||
| 174 | Assert(ppsgList); | ||
| 175 | |||
| 176 | HRESULT hr = S_OK; | ||
| 177 | UINT er = ERROR_SUCCESS; | ||
| 178 | PMSIHANDLE hView, hRec, hGroupRec, hGroupGroupView; | ||
| 179 | |||
| 180 | LPWSTR pwzData = NULL; | ||
| 181 | |||
| 182 | BOOL fGroupGroupExists = FALSE; | ||
| 183 | |||
| 184 | SCA_GROUP *psg = NULL; | ||
| 185 | |||
| 186 | INSTALLSTATE isInstalled, isAction; | ||
| 187 | |||
| 188 | if (S_OK != WcaTableExists(L"Wix4Group")) | ||
| 189 | { | ||
| 190 | WcaLog(LOGMSG_VERBOSE, "Wix4Group Table does not exist, exiting"); | ||
| 191 | ExitFunction1(hr = S_FALSE); | ||
| 192 | } | ||
| 193 | if (S_OK != WcaTableExists(L"Wix6Group")) | ||
| 194 | { | ||
| 195 | WcaLog(LOGMSG_VERBOSE, "Wix6Group Table does not exist, exiting"); | ||
| 196 | ExitFunction1(hr = S_FALSE); | ||
| 197 | } | ||
| 198 | |||
| 199 | if (S_OK == WcaTableExists(L"Wix6GroupGroup")) | ||
| 200 | { | ||
| 201 | fGroupGroupExists = TRUE; | ||
| 202 | } | ||
| 203 | |||
| 204 | // | ||
| 205 | // loop through all the groups | ||
| 206 | // | ||
| 207 | hr = WcaOpenExecuteView(vActionableGroupQuery, &hView); | ||
| 208 | ExitOnFailure(hr, "failed to open view on Wix4Group,Wix6Group table(s)"); | ||
| 209 | while (S_OK == (hr = WcaFetchRecord(hView, &hRec))) | ||
| 210 | { | ||
| 211 | hr = WcaGetRecordString(hRec, vagqComponent, &pwzData); | ||
| 212 | ExitOnFailure(hr, "failed to get Wix4Group.Component"); | ||
| 213 | |||
| 214 | er = ::MsiGetComponentStateW(WcaGetInstallHandle(), pwzData, &isInstalled, &isAction); | ||
| 215 | hr = HRESULT_FROM_WIN32(er); | ||
| 216 | ExitOnFailure(hr, "failed to get Component state for Wix4Group"); | ||
| 217 | |||
| 218 | // don't bother if we aren't installing or uninstalling this component | ||
| 219 | if (WcaIsInstalling(isInstalled, isAction) || WcaIsUninstalling(isInstalled, isAction)) | ||
| 220 | { | ||
| 221 | // | ||
| 222 | // Add the group to the list and populate it's values | ||
| 223 | // | ||
| 224 | hr = AddGroupToList(ppsgList); | ||
| 225 | ExitOnFailure(hr, "failed to add group to list"); | ||
| 226 | |||
| 227 | psg = *ppsgList; | ||
| 228 | |||
| 229 | psg->isInstalled = isInstalled; | ||
| 230 | psg->isAction = isAction; | ||
| 231 | hr = ::StringCchCopyW(psg->wzComponent, countof(psg->wzComponent), pwzData); | ||
| 232 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); | ||
| 233 | |||
| 234 | hr = WcaGetRecordString(hRec, vagqGroup, &pwzData); | ||
| 235 | ExitOnFailure(hr, "failed to get Wix4Group.Group"); | ||
| 236 | hr = ::StringCchCopyW(psg->wzKey, countof(psg->wzKey), pwzData); | ||
| 237 | ExitOnFailure(hr, "failed to copy group key: %ls", pwzData); | ||
| 238 | |||
| 239 | hr = WcaGetRecordFormattedString(hRec, vagqName, &pwzData); | ||
| 240 | ExitOnFailure(hr, "failed to get Wix4Group.Name"); | ||
| 241 | hr = ::StringCchCopyW(psg->wzName, countof(psg->wzName), pwzData); | ||
| 242 | ExitOnFailure(hr, "failed to copy group name: %ls", pwzData); | ||
| 243 | |||
| 244 | hr = WcaGetRecordFormattedString(hRec, vagqDomain, &pwzData); | ||
| 245 | ExitOnFailure(hr, "failed to get Wix4Group.Domain"); | ||
| 246 | hr = ::StringCchCopyW(psg->wzDomain, countof(psg->wzDomain), pwzData); | ||
| 247 | ExitOnFailure(hr, "failed to copy group domain: %ls", pwzData); | ||
| 248 | hr = WcaGetRecordFormattedString(hRec, vagqComment, &pwzData); | ||
| 249 | ExitOnFailure(hr, "failed to get Wix6Group.Comment"); | ||
| 250 | hr = ::StringCchCopyW(psg->wzComment, countof(psg->wzComment), pwzData); | ||
| 251 | ExitOnFailure(hr, "failed to copy group comment: %ls", pwzData); | ||
| 252 | |||
| 253 | hr = WcaGetRecordInteger(hRec, vagqAttributes, &psg->iAttributes); | ||
| 254 | ExitOnFailure(hr, "failed to get Wix6Group.Attributes"); | ||
| 255 | |||
| 256 | // Check if this group is to be added to any other groups | ||
| 257 | if (fGroupGroupExists) | ||
| 258 | { | ||
| 259 | hGroupRec = ::MsiCreateRecord(1); | ||
| 260 | hr = WcaSetRecordString(hGroupRec, 1, psg->wzKey); | ||
| 261 | ExitOnFailure(hr, "Failed to create group record for querying Wix6GroupGroup table"); | ||
| 262 | |||
| 263 | hr = WcaOpenExecuteView(vcsGroupGroupQuery, &hGroupGroupView); | ||
| 264 | ExitOnFailure(hr, "Failed to open view on Wix6GroupGroup table for group %ls", psg->wzKey);/* | ||
| 265 | hr = WcaExecuteView(hGroupGroupView, hGroupRec); | ||
| 266 | ExitOnFailure(hr, "Failed to execute view on Wix6GroupGroup table for group: %ls", psg->wzKey);*/ | ||
| 267 | |||
| 268 | while (S_OK == (hr = WcaFetchRecord(hGroupGroupView, &hRec))) | ||
| 269 | { | ||
| 270 | hr = WcaGetRecordString(hRec, vggqParent, &pwzData); | ||
| 271 | ExitOnFailure(hr, "failed to get Wix6GroupGroup.Parent"); | ||
| 272 | |||
| 273 | hr = AddGroupToList(&(psg->psgGroups)); | ||
| 274 | ExitOnFailure(hr, "failed to add group to list"); | ||
| 275 | |||
| 276 | hr = ScaGetGroup(pwzData, psg->psgGroups); | ||
| 277 | ExitOnFailure(hr, "failed to get information for group: %ls", pwzData); | ||
| 278 | } | ||
| 279 | |||
| 280 | if (E_NOMOREITEMS == hr) | ||
| 281 | { | ||
| 282 | hr = S_OK; | ||
| 283 | } | ||
| 284 | ExitOnFailure(hr, "failed to enumerate selected rows from Wix4UserGroup table"); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | if (E_NOMOREITEMS == hr) | ||
| 290 | { | ||
| 291 | hr = S_OK; | ||
| 292 | } | ||
| 293 | ExitOnFailure(hr, "failed to enumerate selected rows from Wix4Group table"); | ||
| 294 | |||
| 295 | LExit: | ||
| 296 | ReleaseStr(pwzData); | ||
| 297 | |||
| 298 | return hr; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* **************************************************************** | ||
| 302 | ScaGroupExecute - Schedules group account creation or removal based on | ||
| 303 | component state. | ||
| 304 | |||
| 305 | ******************************************************************/ | ||
| 306 | HRESULT ScaGroupExecute( | ||
| 307 | __in SCA_GROUP *psgList | ||
| 308 | ) | ||
| 309 | { | ||
| 310 | HRESULT hr = S_OK; | ||
| 311 | DWORD er = 0; | ||
| 312 | |||
| 313 | LPWSTR pwzBaseScriptKey = NULL; | ||
| 314 | DWORD cScriptKey = 0; | ||
| 315 | |||
| 316 | LOCALGROUP_INFO_0 *pGroupInfo = NULL; | ||
| 317 | LPWSTR pwzScriptKey = NULL; | ||
| 318 | LPWSTR pwzActionData = NULL; | ||
| 319 | LPWSTR pwzRollbackData = NULL; | ||
| 320 | LPWSTR pwzServerName = NULL; | ||
| 321 | |||
| 322 | // Get the base script key for this CustomAction. | ||
| 323 | hr = WcaCaScriptCreateKey(&pwzBaseScriptKey); | ||
| 324 | ExitOnFailure(hr, "Failed to get encoding key."); | ||
| 325 | |||
| 326 | // Loop through all the users to be configured. | ||
| 327 | for (SCA_GROUP *psg = psgList; psg; psg = psg->psgNext) | ||
| 328 | { | ||
| 329 | GROUP_EXISTS geGroupExists = GROUP_EXISTS_INDETERMINATE; | ||
| 330 | |||
| 331 | // Always put the Group Name, Domain, and Comment on the front of the CustomAction data. | ||
| 332 | // The attributes will be added when we have finished adjusting them. Sometimes we'll | ||
| 333 | // add more data. | ||
| 334 | Assert(psg->wzName); | ||
| 335 | hr = WcaWriteStringToCaData(psg->wzName, &pwzActionData); | ||
| 336 | ExitOnFailure(hr, "Failed to add group name to custom action data: %ls", psg->wzName); | ||
| 337 | hr = WcaWriteStringToCaData(psg->wzDomain, &pwzActionData); | ||
| 338 | ExitOnFailure(hr, "Failed to add group domain to custom action data: %ls", psg->wzDomain); | ||
| 339 | hr = WcaWriteStringToCaData(psg->wzComment, &pwzActionData); | ||
| 340 | ExitOnFailure(hr, "Failed to add group comment to custom action data: %ls", psg->wzComment); | ||
| 341 | |||
| 342 | // Check to see if the group already exists since we have to be very careful when adding | ||
| 343 | // and removing groups. Note: MSDN says that it is safe to call these APIs from any | ||
| 344 | // user, so we should be safe calling it during immediate mode. | ||
| 345 | |||
| 346 | LPCWSTR wzDomain = psg->wzDomain; | ||
| 347 | hr = GetDomainServerName(wzDomain, &pwzServerName); | ||
| 348 | |||
| 349 | er = ::NetLocalGroupGetInfo(pwzServerName, psg->wzName, 0, reinterpret_cast<LPBYTE*>(&pGroupInfo)); | ||
| 350 | if (NERR_Success == er) | ||
| 351 | { | ||
| 352 | geGroupExists = GROUP_EXISTS_YES; | ||
| 353 | } | ||
| 354 | else if (NERR_GroupNotFound == er) | ||
| 355 | { | ||
| 356 | geGroupExists = GROUP_EXISTS_NO; | ||
| 357 | } | ||
| 358 | else | ||
| 359 | { | ||
| 360 | geGroupExists = GROUP_EXISTS_INDETERMINATE; | ||
| 361 | hr = HRESULT_FROM_WIN32(er); | ||
| 362 | WcaLog(LOGMSG_VERBOSE, "Failed to check existence of domain: %ls, group: %ls (error code 0x%x) - continuing", wzDomain, psg->wzName, hr); | ||
| 363 | hr = S_OK; | ||
| 364 | er = ERROR_SUCCESS; | ||
| 365 | } | ||
| 366 | |||
| 367 | if (WcaIsInstalling(psg->isInstalled, psg->isAction)) | ||
| 368 | { | ||
| 369 | // If the group exists, check to see if we are supposed to fail if the group exists before | ||
| 370 | // the install. | ||
| 371 | if (GROUP_EXISTS_YES == geGroupExists) | ||
| 372 | { | ||
| 373 | // Re-installs will always fail if we don't remove the check for "fail if exists". | ||
| 374 | if (WcaIsReInstalling(psg->isInstalled, psg->isAction)) | ||
| 375 | { | ||
| 376 | psg->iAttributes &= ~SCAG_FAIL_IF_EXISTS; | ||
| 377 | |||
| 378 | // If install would create the group, re-install should be able to update the group. | ||
| 379 | if (!(psg->iAttributes & SCAG_DONT_CREATE_GROUP)) | ||
| 380 | { | ||
| 381 | psg->iAttributes |= SCAG_UPDATE_IF_EXISTS; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | if (SCAG_FAIL_IF_EXISTS & psg->iAttributes | ||
| 386 | && !(SCAG_UPDATE_IF_EXISTS & psg->iAttributes)) | ||
| 387 | { | ||
| 388 | hr = HRESULT_FROM_WIN32(NERR_GroupExists); | ||
| 389 | MessageExitOnFailure(hr, msierrGRPFailedGroupCreateExists, "Failed to create group: %ls because group already exists.", psg->wzName); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); | ||
| 394 | ExitOnFailure(hr, "failed to add group attributes to custom action data for group: %ls", psg->wzKey); | ||
| 395 | |||
| 396 | // Rollback only if the group already exists, we couldn't determine if the group exists, or we are going to create the group | ||
| 397 | if ((GROUP_EXISTS_YES == geGroupExists) | ||
| 398 | || (GROUP_EXISTS_INDETERMINATE == geGroupExists) | ||
| 399 | || !(psg->iAttributes & SCAG_DONT_CREATE_GROUP)) | ||
| 400 | { | ||
| 401 | ++cScriptKey; | ||
| 402 | hr = StrAllocFormatted(&pwzScriptKey, L"%ls%u", pwzBaseScriptKey, cScriptKey); | ||
| 403 | ExitOnFailure(hr, "Failed to create encoding key."); | ||
| 404 | |||
| 405 | // Write the script key to CustomActionData for install and rollback so information can be passed to rollback. | ||
| 406 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzActionData); | ||
| 407 | ExitOnFailure(hr, "Failed to add encoding key to custom action data."); | ||
| 408 | |||
| 409 | hr = WcaWriteStringToCaData(pwzScriptKey, &pwzRollbackData); | ||
| 410 | ExitOnFailure(hr, "Failed to add encoding key to rollback custom action data."); | ||
| 411 | |||
| 412 | INT iRollbackUserAttributes = psg->iAttributes; | ||
| 413 | |||
| 414 | // If the user already exists, ensure this is accounted for in rollback | ||
| 415 | if (GROUP_EXISTS_YES == geGroupExists) | ||
| 416 | { | ||
| 417 | iRollbackUserAttributes |= SCAG_DONT_CREATE_GROUP; | ||
| 418 | } | ||
| 419 | else | ||
| 420 | { | ||
| 421 | iRollbackUserAttributes &= ~SCAG_DONT_CREATE_GROUP; | ||
| 422 | } | ||
| 423 | |||
| 424 | hr = WcaWriteStringToCaData(psg->wzName, &pwzRollbackData); | ||
| 425 | ExitOnFailure(hr, "Failed to add group name to rollback custom action data: %ls", psg->wzName); | ||
| 426 | hr = WcaWriteStringToCaData(psg->wzDomain, &pwzRollbackData); | ||
| 427 | ExitOnFailure(hr, "Failed to add group domain to rollback custom action data: %ls", psg->wzDomain); | ||
| 428 | hr = WcaWriteIntegerToCaData(iRollbackUserAttributes, &pwzRollbackData); | ||
| 429 | ExitOnFailure(hr, "failed to add group attributes to rollback custom action data for group: %ls", psg->wzKey); | ||
| 430 | |||
| 431 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroupRollback"), pwzRollbackData, COST_GROUP_DELETE); | ||
| 432 | ExitOnFailure(hr, "failed to schedule CreateGroupRollback"); | ||
| 433 | } | ||
| 434 | else | ||
| 435 | { | ||
| 436 | // Write empty script key to CustomActionData since there is no rollback. | ||
| 437 | hr = WcaWriteStringToCaData(L"", &pwzActionData); | ||
| 438 | ExitOnFailure(hr, "Failed to add empty encoding key to custom action data."); | ||
| 439 | } | ||
| 440 | |||
| 441 | // | ||
| 442 | // Schedule the creation now. | ||
| 443 | // | ||
| 444 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"CreateGroup"), pwzActionData, COST_GROUP_ADD); | ||
| 445 | ExitOnFailure(hr, "failed to schedule CreateGroup"); | ||
| 446 | } | ||
| 447 | else if (((GROUP_EXISTS_YES == geGroupExists) | ||
| 448 | || (GROUP_EXISTS_INDETERMINATE == geGroupExists)) | ||
| 449 | && WcaIsUninstalling(psg->isInstalled, psg->isAction) | ||
| 450 | && !(psg->iAttributes & SCAG_DONT_REMOVE_ON_UNINSTALL)) | ||
| 451 | { | ||
| 452 | hr = WcaWriteIntegerToCaData(psg->iAttributes, &pwzActionData); | ||
| 453 | ExitOnFailure(hr, "failed to add group attributes to custom action data for group: %ls", psg->wzKey); | ||
| 454 | |||
| 455 | // Schedule the removal because the group exists and we don't have any flags set | ||
| 456 | // that say not to remove the group on uninstall. | ||
| 457 | // | ||
| 458 | // Note: We can't rollback the removal of a group which is why RemoveGroup is a commit | ||
| 459 | // CustomAction. | ||
| 460 | hr = WcaDoDeferredAction(CUSTOM_ACTION_DECORATION(L"RemoveGroup"), pwzActionData, COST_GROUP_DELETE); | ||
| 461 | ExitOnFailure(hr, "failed to schedule RemoveGroup"); | ||
| 462 | } | ||
| 463 | |||
| 464 | ReleaseNullStr(pwzScriptKey); | ||
| 465 | ReleaseNullStr(pwzActionData); | ||
| 466 | ReleaseNullStr(pwzRollbackData); | ||
| 467 | ReleaseNullStr(pwzServerName); | ||
| 468 | if (pGroupInfo) | ||
| 469 | { | ||
| 470 | ::NetApiBufferFree(static_cast<LPVOID>(pGroupInfo)); | ||
| 471 | pGroupInfo = NULL; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | LExit: | ||
| 476 | ReleaseStr(pwzBaseScriptKey); | ||
| 477 | ReleaseStr(pwzScriptKey); | ||
| 478 | ReleaseStr(pwzActionData); | ||
| 479 | ReleaseStr(pwzRollbackData); | ||
| 480 | ReleaseStr(pwzServerName); | ||
| 481 | if (pGroupInfo) | ||
| 482 | { | ||
| 483 | ::NetApiBufferFree(static_cast<LPVOID>(pGroupInfo)); | ||
| 484 | pGroupInfo = NULL; | ||
| 485 | } | ||
| 486 | |||
| 487 | return hr; | ||
| 488 | } | ||
| 489 | |||
| 490 | static HRESULT AddGroupToList( | ||
| 491 | __inout SCA_GROUP** ppsgList | ||
| 492 | ) | ||
| 493 | { | ||
| 494 | HRESULT hr = S_OK; | ||
| 495 | SCA_GROUP* psg = static_cast<SCA_GROUP*>(MemAlloc(sizeof(SCA_GROUP), TRUE)); | ||
| 496 | ExitOnNull(psg, hr, E_OUTOFMEMORY, "failed to allocate memory for new group list element"); | ||
| 497 | |||
| 498 | psg->psgNext = *ppsgList; | ||
| 499 | *ppsgList = psg; | ||
| 500 | |||
| 501 | LExit: | ||
| 502 | return hr; | ||
| 503 | } | ||
diff --git a/src/ext/Util/ca/scagroup.h b/src/ext/Util/ca/scagroup.h new file mode 100644 index 00000000..8666d852 --- /dev/null +++ b/src/ext/Util/ca/scagroup.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | enum GROUP_EXISTS | ||
| 5 | { | ||
| 6 | GROUP_EXISTS_YES, | ||
| 7 | GROUP_EXISTS_NO, | ||
| 8 | GROUP_EXISTS_INDETERMINATE | ||
| 9 | }; | ||
| 10 | |||
| 11 | // structs | ||
| 12 | struct SCA_GROUP | ||
| 13 | { | ||
| 14 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 15 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 16 | INSTALLSTATE isInstalled; | ||
| 17 | INSTALLSTATE isAction; | ||
| 18 | |||
| 19 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 20 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 21 | WCHAR wzComment[MAX_DARWIN_COLUMN + 1]; | ||
| 22 | INT iAttributes; | ||
| 23 | |||
| 24 | SCA_GROUP* psgGroups; | ||
| 25 | |||
| 26 | SCA_GROUP *psgNext; | ||
| 27 | }; | ||
| 28 | |||
| 29 | // prototypes | ||
| 30 | HRESULT __stdcall ScaGetGroup( | ||
| 31 | __in LPCWSTR wzGroup, | ||
| 32 | __out SCA_GROUP* pscag | ||
| 33 | ); | ||
| 34 | HRESULT __stdcall ScaGetGroupDeferred( | ||
| 35 | __in LPCWSTR wzGroup, | ||
| 36 | __in WCA_WRAPQUERY_HANDLE hGroupQuery, | ||
| 37 | __out SCA_GROUP* pscag | ||
| 38 | ); | ||
| 39 | void ScaGroupFreeList( | ||
| 40 | __in SCA_GROUP* psgList | ||
| 41 | ); | ||
| 42 | HRESULT ScaGroupRead( | ||
| 43 | __inout SCA_GROUP** ppsgList | ||
| 44 | ); | ||
| 45 | HRESULT ScaGroupExecute( | ||
| 46 | __in SCA_GROUP*psgList | ||
| 47 | ); | ||
diff --git a/src/ext/Util/ca/scanet.cpp b/src/ext/Util/ca/scanet.cpp new file mode 100644 index 00000000..11ee487d --- /dev/null +++ b/src/ext/Util/ca/scanet.cpp | |||
| @@ -0,0 +1,50 @@ | |||
| 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 | #include "precomp.h" | ||
| 4 | #include "scanet.h" | ||
| 5 | |||
| 6 | |||
| 7 | HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags) | ||
| 8 | { | ||
| 9 | DWORD er = ERROR_SUCCESS; | ||
| 10 | PDOMAIN_CONTROLLER_INFOW pDomainControllerInfo = NULL; | ||
| 11 | HRESULT hr = S_OK; | ||
| 12 | |||
| 13 | if (pwzDomain && *pwzDomain) | ||
| 14 | { | ||
| 15 | er = ::DsGetDcNameW(NULL, pwzDomain, NULL, NULL, flags, &pDomainControllerInfo); | ||
| 16 | if (RPC_S_SERVER_UNAVAILABLE == er) | ||
| 17 | { | ||
| 18 | // MSDN says, if we get the above error code, try again with the "DS_FORCE_REDISCOVERY" flag | ||
| 19 | er = ::DsGetDcNameW(NULL, pwzDomain, NULL, NULL, flags | DS_FORCE_REDISCOVERY, &pDomainControllerInfo); | ||
| 20 | } | ||
| 21 | |||
| 22 | if (ERROR_SUCCESS == er && pDomainControllerInfo->DomainControllerName) | ||
| 23 | { | ||
| 24 | // Skip the \\ prefix if present. | ||
| 25 | if ('\\' == *pDomainControllerInfo->DomainControllerName && '\\' == *pDomainControllerInfo->DomainControllerName + 1) | ||
| 26 | { | ||
| 27 | hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName + 2, 0); | ||
| 28 | ExitOnFailure(hr, "failed to allocate memory for string"); | ||
| 29 | } | ||
| 30 | else | ||
| 31 | { | ||
| 32 | hr = StrAllocString(ppwzServerName, pDomainControllerInfo->DomainControllerName, 0); | ||
| 33 | ExitOnFailure(hr, "failed to allocate memory for string"); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | else | ||
| 37 | { | ||
| 38 | StrAllocString(ppwzServerName, pwzDomain, 0); | ||
| 39 | hr = HRESULT_FROM_WIN32(er); | ||
| 40 | ExitOnFailure(hr, "failed to contact domain %ls", pwzDomain); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | LExit: | ||
| 45 | if (pDomainControllerInfo) | ||
| 46 | { | ||
| 47 | ::NetApiBufferFree((LPVOID)pDomainControllerInfo); | ||
| 48 | } | ||
| 49 | return hr; | ||
| 50 | } | ||
diff --git a/src/ext/Util/ca/scanet.h b/src/ext/Util/ca/scanet.h new file mode 100644 index 00000000..1fee61f8 --- /dev/null +++ b/src/ext/Util/ca/scanet.h | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | #pragma once | ||
| 2 | // 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. | ||
| 3 | |||
| 4 | HRESULT GetDomainServerName(LPCWSTR pwzDomain, LPWSTR* ppwzServerName, ULONG flags = 0); | ||
diff --git a/src/ext/Util/ca/scasched.cpp b/src/ext/Util/ca/scasched.cpp index d81b1f14..1351fbfd 100644 --- a/src/ext/Util/ca/scasched.cpp +++ b/src/ext/Util/ca/scasched.cpp | |||
| @@ -124,4 +124,49 @@ LExit: | |||
| 124 | 124 | ||
| 125 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | 125 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; |
| 126 | return WcaFinalize(er); | 126 | return WcaFinalize(er); |
| 127 | } \ No newline at end of file | 127 | } |
| 128 | |||
| 129 | /******************************************************************** | ||
| 130 | ConfigureGroups - CUSTOM ACTION ENTRY POINT for installing groups | ||
| 131 | |||
| 132 | ********************************************************************/ | ||
| 133 | extern "C" UINT __stdcall ConfigureGroups( | ||
| 134 | __in MSIHANDLE hInstall | ||
| 135 | ) | ||
| 136 | { | ||
| 137 | //AssertSz(0, "Debug ConfigureGroups"); | ||
| 138 | |||
| 139 | HRESULT hr = S_OK; | ||
| 140 | UINT er = ERROR_SUCCESS; | ||
| 141 | |||
| 142 | BOOL fInitializedCom = FALSE; | ||
| 143 | SCA_GROUP* psgList = NULL; | ||
| 144 | |||
| 145 | // initialize | ||
| 146 | hr = WcaInitialize(hInstall, "ConfigureGroups"); | ||
| 147 | ExitOnFailure(hr, "Failed to initialize"); | ||
| 148 | |||
| 149 | hr = ::CoInitialize(NULL); | ||
| 150 | ExitOnFailure(hr, "failed to initialize COM"); | ||
| 151 | fInitializedCom = TRUE; | ||
| 152 | |||
| 153 | hr = ScaGroupRead(&psgList); | ||
| 154 | ExitOnFailure(hr, "failed to read Wix4Group,Wix6Group table(s)"); | ||
| 155 | |||
| 156 | hr = ScaGroupExecute(psgList); | ||
| 157 | ExitOnFailure(hr, "failed to add/remove Group actions"); | ||
| 158 | |||
| 159 | LExit: | ||
| 160 | if (psgList) | ||
| 161 | { | ||
| 162 | ScaGroupFreeList(psgList); | ||
| 163 | } | ||
| 164 | |||
| 165 | if (fInitializedCom) | ||
| 166 | { | ||
| 167 | ::CoUninitialize(); | ||
| 168 | } | ||
| 169 | |||
| 170 | er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE; | ||
| 171 | return WcaFinalize(er); | ||
| 172 | } | ||
diff --git a/src/ext/Util/ca/scauser.cpp b/src/ext/Util/ca/scauser.cpp index 79da155f..21911e48 100644 --- a/src/ext/Util/ca/scauser.cpp +++ b/src/ext/Util/ca/scauser.cpp | |||
| @@ -5,9 +5,6 @@ | |||
| 5 | LPCWSTR vcsUserQuery = L"SELECT `User`, `Component_`, `Name`, `Domain`, `Comment`, `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, vuqComment, 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`=?"; | ||
| 9 | enum eGroupQuery { vgqGroup = 1, vgqComponent, vgqName, vgqDomain }; | ||
| 10 | |||
| 11 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; | 8 | LPCWSTR vcsUserGroupQuery = L"SELECT `User_`, `Group_` FROM `Wix4UserGroup` WHERE `User_`=?"; |
| 12 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; | 9 | enum eUserGroupQuery { vugqUser = 1, vugqGroup }; |
| 13 | 10 | ||
| @@ -185,71 +182,6 @@ LExit: | |||
| 185 | return hr; | 182 | return hr; |
| 186 | } | 183 | } |
| 187 | 184 | ||
| 188 | |||
| 189 | HRESULT __stdcall ScaGetGroup( | ||
| 190 | __in LPCWSTR wzGroup, | ||
| 191 | __out SCA_GROUP* pscag | ||
| 192 | ) | ||
| 193 | { | ||
| 194 | if (!wzGroup || !pscag) | ||
| 195 | { | ||
| 196 | return E_INVALIDARG; | ||
| 197 | } | ||
| 198 | |||
| 199 | HRESULT hr = S_OK; | ||
| 200 | PMSIHANDLE hView, hRec; | ||
| 201 | |||
| 202 | LPWSTR pwzData = NULL; | ||
| 203 | |||
| 204 | hRec = ::MsiCreateRecord(1); | ||
| 205 | hr = WcaSetRecordString(hRec, 1, wzGroup); | ||
| 206 | ExitOnFailure(hr, "Failed to look up Group"); | ||
| 207 | |||
| 208 | hr = WcaOpenView(vcsGroupQuery, &hView); | ||
| 209 | ExitOnFailure(hr, "Failed to open view on Wix4Group table"); | ||
| 210 | hr = WcaExecuteView(hView, hRec); | ||
| 211 | ExitOnFailure(hr, "Failed to execute view on Wix4Group table"); | ||
| 212 | |||
| 213 | hr = WcaFetchSingleRecord(hView, &hRec); | ||
| 214 | if (S_OK == hr) | ||
| 215 | { | ||
| 216 | hr = WcaGetRecordString(hRec, vgqGroup, &pwzData); | ||
| 217 | ExitOnFailure(hr, "Failed to get Wix4Group.Group."); | ||
| 218 | hr = ::StringCchCopyW(pscag->wzKey, countof(pscag->wzKey), pwzData); | ||
| 219 | ExitOnFailure(hr, "Failed to copy Wix4Group.Group."); | ||
| 220 | |||
| 221 | hr = WcaGetRecordString(hRec, vgqComponent, &pwzData); | ||
| 222 | ExitOnFailure(hr, "Failed to get Wix4Group.Component_"); | ||
| 223 | hr = ::StringCchCopyW(pscag->wzComponent, countof(pscag->wzComponent), pwzData); | ||
| 224 | ExitOnFailure(hr, "Failed to copy Wix4Group.Component_."); | ||
| 225 | |||
| 226 | hr = WcaGetRecordFormattedString(hRec, vgqName, &pwzData); | ||
| 227 | ExitOnFailure(hr, "Failed to get Wix4Group.Name"); | ||
| 228 | hr = ::StringCchCopyW(pscag->wzName, countof(pscag->wzName), pwzData); | ||
| 229 | ExitOnFailure(hr, "Failed to copy Wix4Group.Name."); | ||
| 230 | |||
| 231 | hr = WcaGetRecordFormattedString(hRec, vgqDomain, &pwzData); | ||
| 232 | ExitOnFailure(hr, "Failed to get Wix4Group.Domain"); | ||
| 233 | hr = ::StringCchCopyW(pscag->wzDomain, countof(pscag->wzDomain), pwzData); | ||
| 234 | ExitOnFailure(hr, "Failed to copy Wix4Group.Domain."); | ||
| 235 | } | ||
| 236 | else if (E_NOMOREITEMS == hr) | ||
| 237 | { | ||
| 238 | WcaLog(LOGMSG_STANDARD, "Error: Cannot locate Wix4Group.Group='%ls'", wzGroup); | ||
| 239 | hr = E_FAIL; | ||
| 240 | } | ||
| 241 | else | ||
| 242 | { | ||
| 243 | ExitOnFailure(hr, "Error or found multiple matching Wix4Group rows"); | ||
| 244 | } | ||
| 245 | |||
| 246 | LExit: | ||
| 247 | ReleaseStr(pwzData); | ||
| 248 | |||
| 249 | return hr; | ||
| 250 | } | ||
| 251 | |||
| 252 | |||
| 253 | void ScaUserFreeList( | 185 | void ScaUserFreeList( |
| 254 | __in SCA_USER* psuList | 186 | __in SCA_USER* psuList |
| 255 | ) | 187 | ) |
| @@ -266,21 +198,6 @@ void ScaUserFreeList( | |||
| 266 | } | 198 | } |
| 267 | 199 | ||
| 268 | 200 | ||
| 269 | void ScaGroupFreeList( | ||
| 270 | __in SCA_GROUP* psgList | ||
| 271 | ) | ||
| 272 | { | ||
| 273 | SCA_GROUP* psgDelete = psgList; | ||
| 274 | while (psgList) | ||
| 275 | { | ||
| 276 | psgDelete = psgList; | ||
| 277 | psgList = psgList->psgNext; | ||
| 278 | |||
| 279 | MemFree(psgDelete); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | |||
| 284 | HRESULT ScaUserRead( | 201 | HRESULT ScaUserRead( |
| 285 | __out SCA_USER** ppsuList | 202 | __out SCA_USER** ppsuList |
| 286 | ) | 203 | ) |
diff --git a/src/ext/Util/ca/scauser.h b/src/ext/Util/ca/scauser.h index 3da847b5..de690086 100644 --- a/src/ext/Util/ca/scauser.h +++ b/src/ext/Util/ca/scauser.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | // 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 | // 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. |
| 3 | 3 | #include "scagroup.h" | |
| 4 | 4 | ||
| 5 | enum USER_EXISTS | 5 | enum USER_EXISTS |
| 6 | { | 6 | { |
| @@ -9,17 +9,6 @@ enum USER_EXISTS | |||
| 9 | USER_EXISTS_INDETERMINATE | 9 | USER_EXISTS_INDETERMINATE |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | // structs | ||
| 13 | struct SCA_GROUP | ||
| 14 | { | ||
| 15 | WCHAR wzKey[MAX_DARWIN_KEY + 1]; | ||
| 16 | WCHAR wzComponent[MAX_DARWIN_KEY + 1]; | ||
| 17 | |||
| 18 | WCHAR wzDomain[MAX_DARWIN_COLUMN + 1]; | ||
| 19 | WCHAR wzName[MAX_DARWIN_COLUMN + 1]; | ||
| 20 | |||
| 21 | SCA_GROUP *psgNext; | ||
| 22 | }; | ||
| 23 | 12 | ||
| 24 | struct SCA_USER | 13 | struct SCA_USER |
| 25 | { | 14 | { |
| @@ -50,16 +39,9 @@ HRESULT __stdcall ScaGetUserDeferred( | |||
| 50 | __in WCA_WRAPQUERY_HANDLE hUserQuery, | 39 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
| 51 | __out SCA_USER* pscau | 40 | __out SCA_USER* pscau |
| 52 | ); | 41 | ); |
| 53 | HRESULT __stdcall ScaGetGroup( | ||
| 54 | __in LPCWSTR wzGroup, | ||
| 55 | __out SCA_GROUP* pscag | ||
| 56 | ); | ||
| 57 | void ScaUserFreeList( | 42 | void ScaUserFreeList( |
| 58 | __in SCA_USER* psuList | 43 | __in SCA_USER* psuList |
| 59 | ); | 44 | ); |
| 60 | void ScaGroupFreeList( | ||
| 61 | __in SCA_GROUP* psgList | ||
| 62 | ); | ||
| 63 | HRESULT ScaUserRead( | 45 | HRESULT ScaUserRead( |
| 64 | __inout SCA_USER** ppsuList | 46 | __inout SCA_USER** ppsuList |
| 65 | ); | 47 | ); |
diff --git a/src/ext/Util/ca/utilca.def b/src/ext/Util/ca/utilca.def index 96545566..18a19d12 100644 --- a/src/ext/Util/ca/utilca.def +++ b/src/ext/Util/ca/utilca.def | |||
| @@ -43,6 +43,9 @@ EXPORTS | |||
| 43 | UnregisterPerfmon | 43 | UnregisterPerfmon |
| 44 | CreateSmb | 44 | CreateSmb |
| 45 | DropSmb | 45 | DropSmb |
| 46 | CreateGroup | ||
| 47 | CreateGroupRollback | ||
| 48 | RemoveGroup | ||
| 46 | CreateUser | 49 | CreateUser |
| 47 | CreateUserRollback | 50 | CreateUserRollback |
| 48 | RemoveUser | 51 | RemoveUser |
| @@ -51,6 +54,7 @@ EXPORTS | |||
| 51 | ConfigurePerfmonUninstall | 54 | ConfigurePerfmonUninstall |
| 52 | ConfigureSmbInstall | 55 | ConfigureSmbInstall |
| 53 | ConfigureSmbUninstall | 56 | ConfigureSmbUninstall |
| 57 | ConfigureGroups | ||
| 54 | ConfigureUsers | 58 | ConfigureUsers |
| 55 | InstallPerfCounterData | 59 | InstallPerfCounterData |
| 56 | UninstallPerfCounterData | 60 | UninstallPerfCounterData |
diff --git a/src/ext/Util/ca/utilca.vcxproj b/src/ext/Util/ca/utilca.vcxproj index 758f075c..5dbe2792 100644 --- a/src/ext/Util/ca/utilca.vcxproj +++ b/src/ext/Util/ca/utilca.vcxproj | |||
| @@ -61,7 +61,9 @@ | |||
| 61 | <ClCompile Include="RemoveRegistryKeysEx.cpp" /> | 61 | <ClCompile Include="RemoveRegistryKeysEx.cpp" /> |
| 62 | <ClCompile Include="RestartManager.cpp" /> | 62 | <ClCompile Include="RestartManager.cpp" /> |
| 63 | <ClCompile Include="scaexec.cpp" /> | 63 | <ClCompile Include="scaexec.cpp" /> |
| 64 | <ClCompile Include="scagroup.cpp" /> | ||
| 64 | <ClCompile Include="scamanifest.cpp" /> | 65 | <ClCompile Include="scamanifest.cpp" /> |
| 66 | <ClCompile Include="scanet.cpp" /> | ||
| 65 | <ClCompile Include="scaperf.cpp" /> | 67 | <ClCompile Include="scaperf.cpp" /> |
| 66 | <ClCompile Include="scaperfexec.cpp" /> | 68 | <ClCompile Include="scaperfexec.cpp" /> |
| 67 | <ClCompile Include="scasched.cpp" /> | 69 | <ClCompile Include="scasched.cpp" /> |
| @@ -84,6 +86,8 @@ | |||
| 84 | <ClInclude Include="precomp.h" /> | 86 | <ClInclude Include="precomp.h" /> |
| 85 | <ClInclude Include="sca.h" /> | 87 | <ClInclude Include="sca.h" /> |
| 86 | <ClInclude Include="scacost.h" /> | 88 | <ClInclude Include="scacost.h" /> |
| 89 | <ClInclude Include="scagroup.h" /> | ||
| 90 | <ClInclude Include="scanet.h" /> | ||
| 87 | <ClInclude Include="scasmb.h" /> | 91 | <ClInclude Include="scasmb.h" /> |
| 88 | <ClInclude Include="scasmbexec.h" /> | 92 | <ClInclude Include="scasmbexec.h" /> |
| 89 | <ClInclude Include="scauser.h" /> | 93 | <ClInclude Include="scauser.h" /> |
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/Package.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/Package.wxs new file mode 100644 index 00000000..fdbbb9cc --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/Package.wxs | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 2 | <Package Name="CreateGroup" 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="CreateGroup" /> | ||
| 13 | </StandardDirectory> | ||
| 14 | </Fragment> | ||
| 15 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/PackageComponents.wxs b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/PackageComponents.wxs new file mode 100644 index 00000000..ce9ab418 --- /dev/null +++ b/src/ext/Util/test/WixToolsetTest.Util/TestData/CreateGroup/PackageComponents.wxs | |||
| @@ -0,0 +1,80 @@ | |||
| 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:Group Id="TEST_GROUP00" Name="testName00" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 11 | <util:Group Id="TEST_GROUP01" Name="testName01" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 12 | <util:Group Id="TEST_GROUP02" Name="testName02" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no"/> | ||
| 13 | <util:Group Id="TEST_GROUP03" Name="testName03" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 14 | <util:Group Id="TEST_GROUP04" Name="testName04" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 15 | <util:Group Id="TEST_GROUP05" Name="testName05" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 16 | <util:Group Id="TEST_GROUP06" Name="testName06" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 17 | <util:Group Id="TEST_GROUP07" Name="testName07" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="no" /> | ||
| 18 | <util:Group Id="TEST_GROUP08" Name="testName08" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 19 | <util:Group Id="TEST_GROUP09" Name="testName09" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 20 | <util:Group Id="TEST_GROUP10" Name="testName10" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 21 | <util:Group Id="TEST_GROUP11" Name="testName11" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 22 | <util:Group Id="TEST_GROUP12" Name="testName12" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 23 | <util:Group Id="TEST_GROUP13" Name="testName13" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 24 | <util:Group Id="TEST_GROUP14" Name="testName14" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 25 | <util:Group Id="TEST_GROUP15" Name="testName15" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="no" /> | ||
| 26 | <util:Group Id="TEST_GROUP16" Name="testName16" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 27 | <util:Group Id="TEST_GROUP17" Name="testName17" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 28 | <util:Group Id="TEST_GROUP18" Name="testName18" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 29 | <util:Group Id="TEST_GROUP19" Name="testName19" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 30 | <util:Group Id="TEST_GROUP20" Name="testName20" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 31 | <util:Group Id="TEST_GROUP21" Name="testName21" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 32 | <util:Group Id="TEST_GROUP22" Name="testName22" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 33 | <util:Group Id="TEST_GROUP23" Name="testName23" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="no" /> | ||
| 34 | <util:Group Id="TEST_GROUP24" Name="testName24" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 35 | <util:Group Id="TEST_GROUP25" Name="testName25" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 36 | <util:Group Id="TEST_GROUP26" Name="testName26" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 37 | <util:Group Id="TEST_GROUP27" Name="testName27" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 38 | <util:Group Id="TEST_GROUP28" Name="testName28" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 39 | <util:Group Id="TEST_GROUP29" Name="testName29" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 40 | <util:Group Id="TEST_GROUP30" Name="testName30" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 41 | <util:Group Id="TEST_GROUP31" Name="testName31" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="no" /> | ||
| 42 | <util:Group Id="TEST_GROUP32" Name="testName32" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 43 | <util:Group Id="TEST_GROUP33" Name="testName33" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 44 | <util:Group Id="TEST_GROUP34" Name="testName34" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 45 | <util:Group Id="TEST_GROUP35" Name="testName35" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 46 | <util:Group Id="TEST_GROUP36" Name="testName36" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 47 | <util:Group Id="TEST_GROUP37" Name="testName37" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 48 | <util:Group Id="TEST_GROUP38" Name="testName38" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 49 | <util:Group Id="TEST_GROUP39" Name="testName39" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="yes" RemoveComment="yes" /> | ||
| 50 | <util:Group Id="TEST_GROUP40" Name="testName40" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 51 | <util:Group Id="TEST_GROUP41" Name="testName41" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 52 | <util:Group Id="TEST_GROUP42" Name="testName42" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 53 | <util:Group Id="TEST_GROUP43" Name="testName43" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 54 | <util:Group Id="TEST_GROUP44" Name="testName44" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 55 | <util:Group Id="TEST_GROUP45" Name="testName45" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 56 | <util:Group Id="TEST_GROUP46" Name="testName46" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 57 | <util:Group Id="TEST_GROUP47" Name="testName47" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="yes" RemoveComment="yes" /> | ||
| 58 | <util:Group Id="TEST_GROUP48" Name="testName48" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 59 | <util:Group Id="TEST_GROUP49" Name="testName49" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 60 | <util:Group Id="TEST_GROUP50" Name="testName50" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 61 | <util:Group Id="TEST_GROUP51" Name="testName51" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 62 | <util:Group Id="TEST_GROUP52" Name="testName52" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 63 | <util:Group Id="TEST_GROUP53" Name="testName53" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 64 | <util:Group Id="TEST_GROUP54" Name="testName54" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 65 | <util:Group Id="TEST_GROUP55" Name="testName55" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="yes" Vital="no" RemoveComment="yes" /> | ||
| 66 | <util:Group Id="TEST_GROUP56" Name="testName56" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 67 | <util:Group Id="TEST_GROUP57" Name="testName57" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 68 | <util:Group Id="TEST_GROUP58" Name="testName58" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 69 | <util:Group Id="TEST_GROUP59" Name="testName59" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 70 | <util:Group Id="TEST_GROUP60" Name="testName60" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 71 | <util:Group Id="TEST_GROUP61" Name="testName61" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 72 | <util:Group Id="TEST_GROUP62" Name="testName62" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 73 | <util:Group Id="TEST_GROUP63" Name="testName63" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="no" CreateGroup="no" Vital="no" RemoveComment="yes" /> | ||
| 74 | <util:Group Id="TEST_GROUP64" Name="testName64" Comment="Test Comment 1" FailIfExists="no" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" Domain="testDomain00" /> | ||
| 75 | <util:Group Id="TEST_GROUP65" Name="testName65" Comment="Test Comment 1" FailIfExists="yes" UpdateIfExists="no" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" Domain="testDomain01" /> | ||
| 76 | <util:Group Id="TEST_GROUP66" Name="testName66" FailIfExists="no" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" Domain="testDomain02" /> | ||
| 77 | <util:Group Id="TEST_GROUP67" Name="testName67" FailIfExists="yes" UpdateIfExists="yes" RemoveOnUninstall="yes" CreateGroup="yes" Vital="yes" RemoveComment="no" Domain="testDomain03" /> | ||
| 78 | </Component> | ||
| 79 | </Fragment> | ||
| 80 | </Wix> | ||
diff --git a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs index 0a93f3a4..d71dd824 100644 --- a/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs +++ b/src/ext/Util/test/WixToolsetTest.Util/UtilExtensionFixture.cs | |||
| @@ -395,6 +395,159 @@ namespace WixToolsetTest.Util | |||
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | [Fact] | 397 | [Fact] |
| 398 | public void CanCreateUserGroupWithComment() | ||
| 399 | { | ||
| 400 | var folder = TestData.Get(@"TestData\CreateGroup"); | ||
| 401 | var build = new Builder(folder, typeof(UtilExtensionFactory), new[] { folder }); | ||
| 402 | |||
| 403 | var results = build.BuildAndQuery(BuildX64, "Binary", "CustomAction", "Wix4Group", "Wix6Group"); | ||
| 404 | WixAssert.CompareLineByLine(new[] | ||
| 405 | { | ||
| 406 | "Binary:Wix4UtilCA_X64\t[Binary data]", | ||
| 407 | "CustomAction:Wix4ConfigureGroups_X64\t1\tWix4UtilCA_X64\tConfigureGroups\t", | ||
| 408 | "CustomAction:Wix4CreateGroup_X64\t11265\tWix4UtilCA_X64\tCreateGroup\t", | ||
| 409 | "CustomAction:Wix4CreateGroupRollback_X64\t11521\tWix4UtilCA_X64\tCreateGroupRollback\t", | ||
| 410 | "CustomAction:Wix4RemoveGroup_X64\t11841\tWix4UtilCA_X64\tRemoveGroup\t", | ||
| 411 | "Wix4Group:TEST_GROUP00\tComponent1\ttestName00\t", | ||
| 412 | "Wix4Group:TEST_GROUP01\tComponent1\ttestName01\t", | ||
| 413 | "Wix4Group:TEST_GROUP02\tComponent1\ttestName02\t", | ||
| 414 | "Wix4Group:TEST_GROUP03\tComponent1\ttestName03\t", | ||
| 415 | "Wix4Group:TEST_GROUP04\tComponent1\ttestName04\t", | ||
| 416 | "Wix4Group:TEST_GROUP05\tComponent1\ttestName05\t", | ||
| 417 | "Wix4Group:TEST_GROUP06\tComponent1\ttestName06\t", | ||
| 418 | "Wix4Group:TEST_GROUP07\tComponent1\ttestName07\t", | ||
| 419 | "Wix4Group:TEST_GROUP08\tComponent1\ttestName08\t", | ||
| 420 | "Wix4Group:TEST_GROUP09\tComponent1\ttestName09\t", | ||
| 421 | "Wix4Group:TEST_GROUP10\tComponent1\ttestName10\t", | ||
| 422 | "Wix4Group:TEST_GROUP11\tComponent1\ttestName11\t", | ||
| 423 | "Wix4Group:TEST_GROUP12\tComponent1\ttestName12\t", | ||
| 424 | "Wix4Group:TEST_GROUP13\tComponent1\ttestName13\t", | ||
| 425 | "Wix4Group:TEST_GROUP14\tComponent1\ttestName14\t", | ||
| 426 | "Wix4Group:TEST_GROUP15\tComponent1\ttestName15\t", | ||
| 427 | "Wix4Group:TEST_GROUP16\tComponent1\ttestName16\t", | ||
| 428 | "Wix4Group:TEST_GROUP17\tComponent1\ttestName17\t", | ||
| 429 | "Wix4Group:TEST_GROUP18\tComponent1\ttestName18\t", | ||
| 430 | "Wix4Group:TEST_GROUP19\tComponent1\ttestName19\t", | ||
| 431 | "Wix4Group:TEST_GROUP20\tComponent1\ttestName20\t", | ||
| 432 | "Wix4Group:TEST_GROUP21\tComponent1\ttestName21\t", | ||
| 433 | "Wix4Group:TEST_GROUP22\tComponent1\ttestName22\t", | ||
| 434 | "Wix4Group:TEST_GROUP23\tComponent1\ttestName23\t", | ||
| 435 | "Wix4Group:TEST_GROUP24\tComponent1\ttestName24\t", | ||
| 436 | "Wix4Group:TEST_GROUP25\tComponent1\ttestName25\t", | ||
| 437 | "Wix4Group:TEST_GROUP26\tComponent1\ttestName26\t", | ||
| 438 | "Wix4Group:TEST_GROUP27\tComponent1\ttestName27\t", | ||
| 439 | "Wix4Group:TEST_GROUP28\tComponent1\ttestName28\t", | ||
| 440 | "Wix4Group:TEST_GROUP29\tComponent1\ttestName29\t", | ||
| 441 | "Wix4Group:TEST_GROUP30\tComponent1\ttestName30\t", | ||
| 442 | "Wix4Group:TEST_GROUP31\tComponent1\ttestName31\t", | ||
| 443 | "Wix4Group:TEST_GROUP32\tComponent1\ttestName32\t", | ||
| 444 | "Wix4Group:TEST_GROUP33\tComponent1\ttestName33\t", | ||
| 445 | "Wix4Group:TEST_GROUP34\tComponent1\ttestName34\t", | ||
| 446 | "Wix4Group:TEST_GROUP35\tComponent1\ttestName35\t", | ||
| 447 | "Wix4Group:TEST_GROUP36\tComponent1\ttestName36\t", | ||
| 448 | "Wix4Group:TEST_GROUP37\tComponent1\ttestName37\t", | ||
| 449 | "Wix4Group:TEST_GROUP38\tComponent1\ttestName38\t", | ||
| 450 | "Wix4Group:TEST_GROUP39\tComponent1\ttestName39\t", | ||
| 451 | "Wix4Group:TEST_GROUP40\tComponent1\ttestName40\t", | ||
| 452 | "Wix4Group:TEST_GROUP41\tComponent1\ttestName41\t", | ||
| 453 | "Wix4Group:TEST_GROUP42\tComponent1\ttestName42\t", | ||
| 454 | "Wix4Group:TEST_GROUP43\tComponent1\ttestName43\t", | ||
| 455 | "Wix4Group:TEST_GROUP44\tComponent1\ttestName44\t", | ||
| 456 | "Wix4Group:TEST_GROUP45\tComponent1\ttestName45\t", | ||
| 457 | "Wix4Group:TEST_GROUP46\tComponent1\ttestName46\t", | ||
| 458 | "Wix4Group:TEST_GROUP47\tComponent1\ttestName47\t", | ||
| 459 | "Wix4Group:TEST_GROUP48\tComponent1\ttestName48\t", | ||
| 460 | "Wix4Group:TEST_GROUP49\tComponent1\ttestName49\t", | ||
| 461 | "Wix4Group:TEST_GROUP50\tComponent1\ttestName50\t", | ||
| 462 | "Wix4Group:TEST_GROUP51\tComponent1\ttestName51\t", | ||
| 463 | "Wix4Group:TEST_GROUP52\tComponent1\ttestName52\t", | ||
| 464 | "Wix4Group:TEST_GROUP53\tComponent1\ttestName53\t", | ||
| 465 | "Wix4Group:TEST_GROUP54\tComponent1\ttestName54\t", | ||
| 466 | "Wix4Group:TEST_GROUP55\tComponent1\ttestName55\t", | ||
| 467 | "Wix4Group:TEST_GROUP56\tComponent1\ttestName56\t", | ||
| 468 | "Wix4Group:TEST_GROUP57\tComponent1\ttestName57\t", | ||
| 469 | "Wix4Group:TEST_GROUP58\tComponent1\ttestName58\t", | ||
| 470 | "Wix4Group:TEST_GROUP59\tComponent1\ttestName59\t", | ||
| 471 | "Wix4Group:TEST_GROUP60\tComponent1\ttestName60\t", | ||
| 472 | "Wix4Group:TEST_GROUP61\tComponent1\ttestName61\t", | ||
| 473 | "Wix4Group:TEST_GROUP62\tComponent1\ttestName62\t", | ||
| 474 | "Wix4Group:TEST_GROUP63\tComponent1\ttestName63\t", | ||
| 475 | "Wix4Group:TEST_GROUP64\tComponent1\ttestName64\ttestDomain00", | ||
| 476 | "Wix4Group:TEST_GROUP65\tComponent1\ttestName65\ttestDomain01", | ||
| 477 | "Wix4Group:TEST_GROUP66\tComponent1\ttestName66\ttestDomain02", | ||
| 478 | "Wix4Group:TEST_GROUP67\tComponent1\ttestName67\ttestDomain03", | ||
| 479 | "Wix6Group:TEST_GROUP00\tTest Comment 1\t0", | ||
| 480 | "Wix6Group:TEST_GROUP01\tTest Comment 1\t1", | ||
| 481 | "Wix6Group:TEST_GROUP02\t\t2", | ||
| 482 | "Wix6Group:TEST_GROUP03\t\t3", | ||
| 483 | "Wix6Group:TEST_GROUP04\tTest Comment 1\t4", | ||
| 484 | "Wix6Group:TEST_GROUP05\tTest Comment 1\t5", | ||
| 485 | "Wix6Group:TEST_GROUP06\t\t6", | ||
| 486 | "Wix6Group:TEST_GROUP07\t\t7", | ||
| 487 | "Wix6Group:TEST_GROUP08\tTest Comment 1\t8", | ||
| 488 | "Wix6Group:TEST_GROUP09\tTest Comment 1\t9", | ||
| 489 | "Wix6Group:TEST_GROUP10\t\t10", | ||
| 490 | "Wix6Group:TEST_GROUP11\t\t11", | ||
| 491 | "Wix6Group:TEST_GROUP12\tTest Comment 1\t12", | ||
| 492 | "Wix6Group:TEST_GROUP13\tTest Comment 1\t13", | ||
| 493 | "Wix6Group:TEST_GROUP14\t\t14", | ||
| 494 | "Wix6Group:TEST_GROUP15\t\t15", | ||
| 495 | "Wix6Group:TEST_GROUP16\tTest Comment 1\t16", | ||
| 496 | "Wix6Group:TEST_GROUP17\tTest Comment 1\t17", | ||
| 497 | "Wix6Group:TEST_GROUP18\t\t18", | ||
| 498 | "Wix6Group:TEST_GROUP19\t\t19", | ||
| 499 | "Wix6Group:TEST_GROUP20\tTest Comment 1\t20", | ||
| 500 | "Wix6Group:TEST_GROUP21\tTest Comment 1\t21", | ||
| 501 | "Wix6Group:TEST_GROUP22\t\t22", | ||
| 502 | "Wix6Group:TEST_GROUP23\t\t23", | ||
| 503 | "Wix6Group:TEST_GROUP24\tTest Comment 1\t24", | ||
| 504 | "Wix6Group:TEST_GROUP25\tTest Comment 1\t25", | ||
| 505 | "Wix6Group:TEST_GROUP26\t\t26", | ||
| 506 | "Wix6Group:TEST_GROUP27\t\t27", | ||
| 507 | "Wix6Group:TEST_GROUP28\tTest Comment 1\t28", | ||
| 508 | "Wix6Group:TEST_GROUP29\tTest Comment 1\t29", | ||
| 509 | "Wix6Group:TEST_GROUP30\t\t30", | ||
| 510 | "Wix6Group:TEST_GROUP31\t\t31", | ||
| 511 | "Wix6Group:TEST_GROUP32\t\t32", | ||
| 512 | "Wix6Group:TEST_GROUP33\t\t33", | ||
| 513 | "Wix6Group:TEST_GROUP34\t\t34", | ||
| 514 | "Wix6Group:TEST_GROUP35\t\t35", | ||
| 515 | "Wix6Group:TEST_GROUP36\t\t36", | ||
| 516 | "Wix6Group:TEST_GROUP37\t\t37", | ||
| 517 | "Wix6Group:TEST_GROUP38\t\t38", | ||
| 518 | "Wix6Group:TEST_GROUP39\t\t39", | ||
| 519 | "Wix6Group:TEST_GROUP40\t\t40", | ||
| 520 | "Wix6Group:TEST_GROUP41\t\t41", | ||
| 521 | "Wix6Group:TEST_GROUP42\t\t42", | ||
| 522 | "Wix6Group:TEST_GROUP43\t\t43", | ||
| 523 | "Wix6Group:TEST_GROUP44\t\t44", | ||
| 524 | "Wix6Group:TEST_GROUP45\t\t45", | ||
| 525 | "Wix6Group:TEST_GROUP46\t\t46", | ||
| 526 | "Wix6Group:TEST_GROUP47\t\t47", | ||
| 527 | "Wix6Group:TEST_GROUP48\t\t48", | ||
| 528 | "Wix6Group:TEST_GROUP49\t\t49", | ||
| 529 | "Wix6Group:TEST_GROUP50\t\t50", | ||
| 530 | "Wix6Group:TEST_GROUP51\t\t51", | ||
| 531 | "Wix6Group:TEST_GROUP52\t\t52", | ||
| 532 | "Wix6Group:TEST_GROUP53\t\t53", | ||
| 533 | "Wix6Group:TEST_GROUP54\t\t54", | ||
| 534 | "Wix6Group:TEST_GROUP55\t\t55", | ||
| 535 | "Wix6Group:TEST_GROUP56\t\t56", | ||
| 536 | "Wix6Group:TEST_GROUP57\t\t57", | ||
| 537 | "Wix6Group:TEST_GROUP58\t\t58", | ||
| 538 | "Wix6Group:TEST_GROUP59\t\t59", | ||
| 539 | "Wix6Group:TEST_GROUP60\t\t60", | ||
| 540 | "Wix6Group:TEST_GROUP61\t\t61", | ||
| 541 | "Wix6Group:TEST_GROUP62\t\t62", | ||
| 542 | "Wix6Group:TEST_GROUP63\t\t63", | ||
| 543 | "Wix6Group:TEST_GROUP64\tTest Comment 1\t0", | ||
| 544 | "Wix6Group:TEST_GROUP65\tTest Comment 1\t1", | ||
| 545 | "Wix6Group:TEST_GROUP66\t\t2", | ||
| 546 | "Wix6Group:TEST_GROUP67\t\t3", | ||
| 547 | }, results.OrderBy(s => s).ToArray()); | ||
| 548 | } | ||
| 549 | |||
| 550 | [Fact] | ||
| 398 | public void CanCreateUserAccountWithComment() | 551 | public void CanCreateUserAccountWithComment() |
| 399 | { | 552 | { |
| 400 | var folder = TestData.Get(@"TestData\CreateUser"); | 553 | var folder = TestData.Get(@"TestData\CreateUser"); |
diff --git a/src/ext/Util/wixext/Symbols/GroupGroupSymbol.cs b/src/ext/Util/wixext/Symbols/GroupGroupSymbol.cs new file mode 100644 index 00000000..fdd1ee76 --- /dev/null +++ b/src/ext/Util/wixext/Symbols/GroupGroupSymbol.cs | |||
| @@ -0,0 +1,56 @@ | |||
| 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 | namespace WixToolset.Util | ||
| 4 | { | ||
| 5 | using WixToolset.Data; | ||
| 6 | using WixToolset.Util.Symbols; | ||
| 7 | |||
| 8 | public static partial class UtilSymbolDefinitions | ||
| 9 | { | ||
| 10 | public static readonly IntermediateSymbolDefinition GroupGroup = new IntermediateSymbolDefinition( | ||
| 11 | UtilSymbolDefinitionType.GroupGroup.ToString(), | ||
| 12 | new[] | ||
| 13 | { | ||
| 14 | new IntermediateFieldDefinition(nameof(GroupGroupSymbol.SymbolFields.ParentGroupRef), IntermediateFieldType.String), | ||
| 15 | new IntermediateFieldDefinition(nameof(GroupGroupSymbol.SymbolFields.ChildGroupRef), IntermediateFieldType.String), | ||
| 16 | }, | ||
| 17 | typeof(UserGroupSymbol)); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace WixToolset.Util.Symbols | ||
| 22 | { | ||
| 23 | using WixToolset.Data; | ||
| 24 | |||
| 25 | public class GroupGroupSymbol : IntermediateSymbol | ||
| 26 | { | ||
| 27 | public enum SymbolFields | ||
| 28 | { | ||
| 29 | ParentGroupRef, | ||
| 30 | ChildGroupRef, | ||
| 31 | } | ||
| 32 | |||
| 33 | public GroupGroupSymbol() : base(UtilSymbolDefinitions.GroupGroup, null, null) | ||
| 34 | { | ||
| 35 | } | ||
| 36 | |||
| 37 | public GroupGroupSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.GroupGroup, sourceLineNumber, id) | ||
| 38 | { | ||
| 39 | } | ||
| 40 | |||
| 41 | public IntermediateField this[GroupGroupSymbol.SymbolFields index] => this.Fields[(int)index]; | ||
| 42 | |||
| 43 | public string ParentGroupRef | ||
| 44 | { | ||
| 45 | get => this.Fields[(int)GroupGroupSymbol.SymbolFields.ParentGroupRef].AsString(); | ||
| 46 | set => this.Set((int)GroupGroupSymbol.SymbolFields.ParentGroupRef, value); | ||
| 47 | } | ||
| 48 | |||
| 49 | public string ChildGroupRef | ||
| 50 | { | ||
| 51 | get => this.Fields[(int)GroupGroupSymbol.SymbolFields.ChildGroupRef].AsString(); | ||
| 52 | set => this.Set((int)GroupGroupSymbol.SymbolFields.ChildGroupRef, value); | ||
| 53 | } | ||
| 54 | |||
| 55 | } | ||
| 56 | } | ||
diff --git a/src/ext/Util/wixext/Symbols/GroupSymbol.cs b/src/ext/Util/wixext/Symbols/GroupSymbol.cs index b378db44..ef1dc33f 100644 --- a/src/ext/Util/wixext/Symbols/GroupSymbol.cs +++ b/src/ext/Util/wixext/Symbols/GroupSymbol.cs | |||
| @@ -11,27 +11,38 @@ namespace WixToolset.Util | |||
| 11 | UtilSymbolDefinitionType.Group.ToString(), | 11 | UtilSymbolDefinitionType.Group.ToString(), |
| 12 | new[] | 12 | new[] |
| 13 | { | 13 | { |
| 14 | new IntermediateFieldDefinition(nameof(GroupSymbolFields.ComponentRef), IntermediateFieldType.String), | 14 | new IntermediateFieldDefinition(nameof(GroupSymbol.SymbolFields.ComponentRef), IntermediateFieldType.String), |
| 15 | new IntermediateFieldDefinition(nameof(GroupSymbolFields.Name), IntermediateFieldType.String), | 15 | new IntermediateFieldDefinition(nameof(GroupSymbol.SymbolFields.Name), IntermediateFieldType.String), |
| 16 | new IntermediateFieldDefinition(nameof(GroupSymbolFields.Domain), IntermediateFieldType.String), | 16 | new IntermediateFieldDefinition(nameof(GroupSymbol.SymbolFields.Domain), IntermediateFieldType.String), |
| 17 | }, | 17 | }, |
| 18 | typeof(GroupSymbol)); | 18 | typeof(GroupSymbol)); |
| 19 | |||
| 20 | public static readonly IntermediateSymbolDefinition Group6 = new IntermediateSymbolDefinition( | ||
| 21 | UtilSymbolDefinitionType.Group6.ToString(), | ||
| 22 | new[] | ||
| 23 | { | ||
| 24 | new IntermediateFieldDefinition(nameof(Group6Symbol.SymbolFields.GroupRef), IntermediateFieldType.String), | ||
| 25 | new IntermediateFieldDefinition(nameof(Group6Symbol.SymbolFields.Comment), IntermediateFieldType.String), | ||
| 26 | new IntermediateFieldDefinition(nameof(Group6Symbol.SymbolFields.Attributes), IntermediateFieldType.Number), | ||
| 27 | }, | ||
| 28 | typeof(Group6Symbol)); | ||
| 19 | } | 29 | } |
| 20 | } | 30 | } |
| 21 | 31 | ||
| 22 | namespace WixToolset.Util.Symbols | 32 | namespace WixToolset.Util.Symbols |
| 23 | { | 33 | { |
| 34 | using System; | ||
| 24 | using WixToolset.Data; | 35 | using WixToolset.Data; |
| 25 | 36 | ||
| 26 | public enum GroupSymbolFields | ||
| 27 | { | ||
| 28 | ComponentRef, | ||
| 29 | Name, | ||
| 30 | Domain, | ||
| 31 | } | ||
| 32 | |||
| 33 | public class GroupSymbol : IntermediateSymbol | 37 | public class GroupSymbol : IntermediateSymbol |
| 34 | { | 38 | { |
| 39 | public enum SymbolFields | ||
| 40 | { | ||
| 41 | ComponentRef, | ||
| 42 | Name, | ||
| 43 | Domain, | ||
| 44 | } | ||
| 45 | |||
| 35 | public GroupSymbol() : base(UtilSymbolDefinitions.Group, null, null) | 46 | public GroupSymbol() : base(UtilSymbolDefinitions.Group, null, null) |
| 36 | { | 47 | { |
| 37 | } | 48 | } |
| @@ -40,24 +51,74 @@ namespace WixToolset.Util.Symbols | |||
| 40 | { | 51 | { |
| 41 | } | 52 | } |
| 42 | 53 | ||
| 43 | public IntermediateField this[GroupSymbolFields index] => this.Fields[(int)index]; | 54 | public IntermediateField this[GroupSymbol.SymbolFields index] => this.Fields[(int)index]; |
| 44 | 55 | ||
| 45 | public string ComponentRef | 56 | public string ComponentRef |
| 46 | { | 57 | { |
| 47 | get => this.Fields[(int)GroupSymbolFields.ComponentRef].AsString(); | 58 | get => this.Fields[(int)GroupSymbol.SymbolFields.ComponentRef].AsString(); |
| 48 | set => this.Set((int)GroupSymbolFields.ComponentRef, value); | 59 | set => this.Set((int)GroupSymbol.SymbolFields.ComponentRef, value); |
| 49 | } | 60 | } |
| 50 | 61 | ||
| 51 | public string Name | 62 | public string Name |
| 52 | { | 63 | { |
| 53 | get => this.Fields[(int)GroupSymbolFields.Name].AsString(); | 64 | get => this.Fields[(int)GroupSymbol.SymbolFields.Name].AsString(); |
| 54 | set => this.Set((int)GroupSymbolFields.Name, value); | 65 | set => this.Set((int)GroupSymbol.SymbolFields.Name, value); |
| 55 | } | 66 | } |
| 56 | 67 | ||
| 57 | public string Domain | 68 | public string Domain |
| 58 | { | 69 | { |
| 59 | get => this.Fields[(int)GroupSymbolFields.Domain].AsString(); | 70 | get => this.Fields[(int)GroupSymbol.SymbolFields.Domain].AsString(); |
| 60 | set => this.Set((int)GroupSymbolFields.Domain, value); | 71 | set => this.Set((int)GroupSymbol.SymbolFields.Domain, value); |
| 61 | } | 72 | } |
| 62 | } | 73 | } |
| 63 | } \ No newline at end of file | 74 | |
| 75 | public class Group6Symbol : IntermediateSymbol | ||
| 76 | { | ||
| 77 | [Flags] | ||
| 78 | public enum SymbolAttributes | ||
| 79 | { | ||
| 80 | None = 0x00000000, | ||
| 81 | FailIfExists = 0x00000001, | ||
| 82 | UpdateIfExists = 0x00000002, | ||
| 83 | DontRemoveOnUninstall = 0x00000004, | ||
| 84 | DontCreateGroup = 0x00000008, | ||
| 85 | NonVital = 0x00000010, | ||
| 86 | RemoveComment = 0x00000020, | ||
| 87 | } | ||
| 88 | |||
| 89 | public enum SymbolFields | ||
| 90 | { | ||
| 91 | GroupRef, | ||
| 92 | Comment, | ||
| 93 | Attributes, | ||
| 94 | } | ||
| 95 | |||
| 96 | public Group6Symbol() : base(UtilSymbolDefinitions.Group6, null, null) | ||
| 97 | { | ||
| 98 | } | ||
| 99 | |||
| 100 | public Group6Symbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilSymbolDefinitions.Group6, sourceLineNumber, id) | ||
| 101 | { | ||
| 102 | } | ||
| 103 | |||
| 104 | public IntermediateField this[Group6Symbol.SymbolFields index] => this.Fields[(int)index]; | ||
| 105 | |||
| 106 | public string GroupRef | ||
| 107 | { | ||
| 108 | get => this.Fields[(int)Group6Symbol.SymbolFields.GroupRef].AsString(); | ||
| 109 | set => this.Set((int)Group6Symbol.SymbolFields.GroupRef, value); | ||
| 110 | } | ||
| 111 | |||
| 112 | public string Comment | ||
| 113 | { | ||
| 114 | get => this.Fields[(int)Group6Symbol.SymbolFields.Comment].AsString(); | ||
| 115 | set => this.Set((int)Group6Symbol.SymbolFields.Comment, value); | ||
| 116 | } | ||
| 117 | |||
| 118 | public SymbolAttributes Attributes | ||
| 119 | { | ||
| 120 | get => (SymbolAttributes)this.Fields[(int)Group6Symbol.SymbolFields.Attributes].AsNumber(); | ||
| 121 | set => this.Set((int)Group6Symbol.SymbolFields.Attributes, (int)value); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
diff --git a/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs b/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs index 8152868f..43d0fca0 100644 --- a/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs +++ b/src/ext/Util/wixext/Symbols/UtilSymbolDefinitions.cs | |||
| @@ -12,6 +12,8 @@ namespace WixToolset.Util | |||
| 12 | FileShare, | 12 | FileShare, |
| 13 | FileSharePermissions, | 13 | FileSharePermissions, |
| 14 | Group, | 14 | Group, |
| 15 | Group6, | ||
| 16 | GroupGroup, | ||
| 15 | Perfmon, | 17 | Perfmon, |
| 16 | PerfmonManifest, | 18 | PerfmonManifest, |
| 17 | PerformanceCategory, | 19 | PerformanceCategory, |
| @@ -59,6 +61,12 @@ namespace WixToolset.Util | |||
| 59 | case UtilSymbolDefinitionType.Group: | 61 | case UtilSymbolDefinitionType.Group: |
| 60 | return UtilSymbolDefinitions.Group; | 62 | return UtilSymbolDefinitions.Group; |
| 61 | 63 | ||
| 64 | case UtilSymbolDefinitionType.Group6: | ||
| 65 | return UtilSymbolDefinitions.Group6; | ||
| 66 | |||
| 67 | case UtilSymbolDefinitionType.GroupGroup: | ||
| 68 | return UtilSymbolDefinitions.GroupGroup; | ||
| 69 | |||
| 62 | case UtilSymbolDefinitionType.Perfmon: | 70 | case UtilSymbolDefinitionType.Perfmon: |
| 63 | return UtilSymbolDefinitions.Perfmon; | 71 | return UtilSymbolDefinitions.Perfmon; |
| 64 | 72 | ||
diff --git a/src/ext/Util/wixext/UtilCompiler.cs b/src/ext/Util/wixext/UtilCompiler.cs index 3bcd2c0b..aff7dd0d 100644 --- a/src/ext/Util/wixext/UtilCompiler.cs +++ b/src/ext/Util/wixext/UtilCompiler.cs | |||
| @@ -139,6 +139,9 @@ namespace WixToolset.Util | |||
| 139 | case "TouchFile": | 139 | case "TouchFile": |
| 140 | this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64); | 140 | this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64); |
| 141 | break; | 141 | break; |
| 142 | case "Group": | ||
| 143 | this.ParseGroupElement(intermediate, section, element, componentId); | ||
| 144 | break; | ||
| 142 | case "User": | 145 | case "User": |
| 143 | this.ParseUserElement(intermediate, section, element, componentId); | 146 | this.ParseUserElement(intermediate, section, element, componentId); |
| 144 | break; | 147 | break; |
| @@ -1357,6 +1360,8 @@ namespace WixToolset.Util | |||
| 1357 | Identifier id = null; | 1360 | Identifier id = null; |
| 1358 | string domain = null; | 1361 | string domain = null; |
| 1359 | string name = null; | 1362 | string name = null; |
| 1363 | string comment = null; | ||
| 1364 | Group6Symbol.SymbolAttributes attributes = Group6Symbol.SymbolAttributes.None; | ||
| 1360 | 1365 | ||
| 1361 | foreach (var attrib in element.Attributes()) | 1366 | foreach (var attrib in element.Attributes()) |
| 1362 | { | 1367 | { |
| @@ -1373,6 +1378,75 @@ namespace WixToolset.Util | |||
| 1373 | case "Domain": | 1378 | case "Domain": |
| 1374 | domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | 1379 | domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); |
| 1375 | break; | 1380 | break; |
| 1381 | case "Comment": | ||
| 1382 | if (null == componentId) | ||
| 1383 | { | ||
| 1384 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1385 | } | ||
| 1386 | |||
| 1387 | comment = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 1388 | break; | ||
| 1389 | case "CreateGroup": | ||
| 1390 | if (null == componentId) | ||
| 1391 | { | ||
| 1392 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1396 | { | ||
| 1397 | attributes |= Group6Symbol.SymbolAttributes.DontCreateGroup; | ||
| 1398 | } | ||
| 1399 | break; | ||
| 1400 | case "FailIfExists": | ||
| 1401 | if (null == componentId) | ||
| 1402 | { | ||
| 1403 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1407 | { | ||
| 1408 | attributes |= Group6Symbol.SymbolAttributes.FailIfExists; | ||
| 1409 | } | ||
| 1410 | break; | ||
| 1411 | case "UpdateIfExists": | ||
| 1412 | if (null == componentId) | ||
| 1413 | { | ||
| 1414 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1418 | { | ||
| 1419 | attributes |= Group6Symbol.SymbolAttributes.UpdateIfExists; | ||
| 1420 | } | ||
| 1421 | break; | ||
| 1422 | case "RemoveComment": | ||
| 1423 | if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1424 | { | ||
| 1425 | attributes |= Group6Symbol.SymbolAttributes.RemoveComment; | ||
| 1426 | } | ||
| 1427 | break; | ||
| 1428 | case "RemoveOnUninstall": | ||
| 1429 | if (null == componentId) | ||
| 1430 | { | ||
| 1431 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1435 | { | ||
| 1436 | attributes |= Group6Symbol.SymbolAttributes.DontRemoveOnUninstall; | ||
| 1437 | } | ||
| 1438 | break; | ||
| 1439 | case "Vital": | ||
| 1440 | if (null == componentId) | ||
| 1441 | { | ||
| 1442 | this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName)); | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
| 1446 | { | ||
| 1447 | attributes |= Group6Symbol.SymbolAttributes.NonVital; | ||
| 1448 | } | ||
| 1449 | break; | ||
| 1376 | default: | 1450 | default: |
| 1377 | this.ParseHelper.UnexpectedAttribute(element, attrib); | 1451 | this.ParseHelper.UnexpectedAttribute(element, attrib); |
| 1378 | break; | 1452 | break; |
| @@ -1389,7 +1463,40 @@ namespace WixToolset.Util | |||
| 1389 | id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name); | 1463 | id = this.ParseHelper.CreateIdentifier("ugr", componentId, domain, name); |
| 1390 | } | 1464 | } |
| 1391 | 1465 | ||
| 1392 | this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element); | 1466 | if (null == name) |
| 1467 | { | ||
| 1468 | this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name")); | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | if (null != comment && (Group6Symbol.SymbolAttributes.RemoveComment & attributes) != 0) | ||
| 1472 | { | ||
| 1473 | this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Comment", "RemoveComment")); | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | if (null != componentId) | ||
| 1477 | { | ||
| 1478 | this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureGroups", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64); | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | foreach (var child in element.Elements()) | ||
| 1482 | { | ||
| 1483 | if (this.Namespace == child.Name.Namespace) | ||
| 1484 | { | ||
| 1485 | switch (child.Name.LocalName) | ||
| 1486 | { | ||
| 1487 | case "GroupRef": | ||
| 1488 | this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType:true); | ||
| 1489 | break; | ||
| 1490 | default: | ||
| 1491 | //this.ParseHelper.UnexpectedElement(element, child); | ||
| 1492 | break; | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | else | ||
| 1496 | { | ||
| 1497 | this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child); | ||
| 1498 | } | ||
| 1499 | } | ||
| 1393 | 1500 | ||
| 1394 | if (!this.Messaging.EncounteredError) | 1501 | if (!this.Messaging.EncounteredError) |
| 1395 | { | 1502 | { |
| @@ -1399,6 +1506,12 @@ namespace WixToolset.Util | |||
| 1399 | Name = name, | 1506 | Name = name, |
| 1400 | Domain = domain, | 1507 | Domain = domain, |
| 1401 | }); | 1508 | }); |
| 1509 | section.AddSymbol(new Group6Symbol(sourceLineNumbers, id) | ||
| 1510 | { | ||
| 1511 | GroupRef = id.Id, | ||
| 1512 | Comment = comment, | ||
| 1513 | Attributes = attributes, | ||
| 1514 | }); | ||
| 1402 | } | 1515 | } |
| 1403 | } | 1516 | } |
| 1404 | 1517 | ||
| @@ -1406,8 +1519,9 @@ namespace WixToolset.Util | |||
| 1406 | /// Parses a GroupRef element | 1519 | /// Parses a GroupRef element |
| 1407 | /// </summary> | 1520 | /// </summary> |
| 1408 | /// <param name="element">Element to parse.</param> | 1521 | /// <param name="element">Element to parse.</param> |
| 1409 | /// <param name="userId">Required user id to be joined to the group.</param> | 1522 | /// <param name="childId">Required child id to be joined to the group.</param> |
| 1410 | private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId) | 1523 | /// <param name="groupType">whether the child is a group (true) or a user (false)</param> |
| 1524 | private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string childId, bool groupType=false) | ||
| 1411 | { | 1525 | { |
| 1412 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); | 1526 | var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element); |
| 1413 | string groupId = null; | 1527 | string groupId = null; |
| @@ -1437,11 +1551,22 @@ namespace WixToolset.Util | |||
| 1437 | 1551 | ||
| 1438 | if (!this.Messaging.EncounteredError) | 1552 | if (!this.Messaging.EncounteredError) |
| 1439 | { | 1553 | { |
| 1440 | section.AddSymbol(new UserGroupSymbol(sourceLineNumbers) | 1554 | if (!groupType) |
| 1441 | { | 1555 | { |
| 1442 | UserRef = userId, | 1556 | section.AddSymbol(new UserGroupSymbol(sourceLineNumbers) |
| 1443 | GroupRef = groupId, | 1557 | { |
| 1444 | }); | 1558 | UserRef = childId, |
| 1559 | GroupRef = groupId, | ||
| 1560 | }); | ||
| 1561 | } | ||
| 1562 | else | ||
| 1563 | { | ||
| 1564 | section.AddSymbol(new GroupGroupSymbol(sourceLineNumbers) | ||
| 1565 | { | ||
| 1566 | ChildGroupRef = childId, | ||
| 1567 | ParentGroupRef = groupId, | ||
| 1568 | }); | ||
| 1569 | } | ||
| 1445 | } | 1570 | } |
| 1446 | } | 1571 | } |
| 1447 | 1572 | ||
| @@ -3460,7 +3585,7 @@ namespace WixToolset.Util | |||
| 3460 | this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); | 3585 | this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName)); |
| 3461 | } | 3586 | } |
| 3462 | 3587 | ||
| 3463 | this.ParseGroupRefElement(intermediate, section, child, id.Id); | 3588 | this.ParseGroupRefElement(intermediate, section, child, id.Id, groupType:false); |
| 3464 | break; | 3589 | break; |
| 3465 | default: | 3590 | default: |
| 3466 | this.ParseHelper.UnexpectedElement(element, child); | 3591 | this.ParseHelper.UnexpectedElement(element, child); |
diff --git a/src/ext/Util/wixext/UtilDecompiler.cs b/src/ext/Util/wixext/UtilDecompiler.cs index 52b64889..53b75b8d 100644 --- a/src/ext/Util/wixext/UtilDecompiler.cs +++ b/src/ext/Util/wixext/UtilDecompiler.cs | |||
| @@ -176,6 +176,14 @@ namespace WixToolset.Util | |||
| 176 | case "Wix4Group": | 176 | case "Wix4Group": |
| 177 | this.DecompileGroupTable(table); | 177 | this.DecompileGroupTable(table); |
| 178 | break; | 178 | break; |
| 179 | case "Group6": | ||
| 180 | case "Wix6Group": | ||
| 181 | this.DecompileGroup6Table(table); | ||
| 182 | break; | ||
| 183 | case "GroupGroup": | ||
| 184 | case "Wix6GroupGroup": | ||
| 185 | this.DecompileGroupGroup6Table(table); | ||
| 186 | break; | ||
| 179 | case "Perfmon": | 187 | case "Perfmon": |
| 180 | case "Wix4Perfmon": | 188 | case "Wix4Perfmon": |
| 181 | this.DecompilePerfmonTable(table); | 189 | this.DecompilePerfmonTable(table); |
| @@ -427,18 +435,60 @@ namespace WixToolset.Util | |||
| 427 | { | 435 | { |
| 428 | foreach (var row in table.Rows) | 436 | foreach (var row in table.Rows) |
| 429 | { | 437 | { |
| 430 | if (null != row[1]) | ||
| 431 | { | ||
| 432 | this.Messaging.Write(WarningMessages.UnrepresentableColumnValue(row.SourceLineNumbers, table.Name, "Component_", (string)row[1])); | ||
| 433 | } | ||
| 434 | |||
| 435 | this.DecompilerHelper.AddElementToRoot(UtilConstants.GroupName, | 438 | this.DecompilerHelper.AddElementToRoot(UtilConstants.GroupName, |
| 436 | new XAttribute("Id", row.FieldAsString(0)), | 439 | new XAttribute("Id", row.FieldAsString(0)), |
| 437 | new XAttribute("Name", row.FieldAsString(1)), | 440 | new XAttribute("Name", row.FieldAsString(2)), |
| 438 | AttributeIfNotNull("Domain", row, 3) | 441 | AttributeIfNotNull("Domain", row, 3) |
| 439 | ); | 442 | ); |
| 440 | } | 443 | } |
| 441 | } | 444 | } |
| 445 | /// <summary> | ||
| 446 | /// Decompile the Group6 table. | ||
| 447 | /// </summary> | ||
| 448 | /// <param name="table">The table to decompile.</param> | ||
| 449 | private void DecompileGroup6Table(Table table) | ||
| 450 | { | ||
| 451 | foreach (var row in table.Rows) | ||
| 452 | { | ||
| 453 | var groupId = row.FieldAsString(0); | ||
| 454 | if (this.DecompilerHelper.TryGetIndexedElement("Group", groupId, out var group)) | ||
| 455 | { | ||
| 456 | var attributes = (Group6Symbol.SymbolAttributes)(row.FieldAsNullableInteger(2) ?? 0); | ||
| 457 | group.Add(AttributeIfNotNull("Comment", row, 1)); | ||
| 458 | group.Add(AttributeIfTrue("FailIfExists", ((attributes & Group6Symbol.SymbolAttributes.FailIfExists) != 0))); | ||
| 459 | group.Add(AttributeIfTrue("UpdateIfExists", ((attributes & Group6Symbol.SymbolAttributes.UpdateIfExists) != 0))); | ||
| 460 | group.Add(AttributeIfTrue("DontRemoveOnUninstall", ((attributes & Group6Symbol.SymbolAttributes.DontRemoveOnUninstall) != 0))); | ||
| 461 | group.Add(AttributeIfTrue("DontCreateGroup", ((attributes & Group6Symbol.SymbolAttributes.DontCreateGroup) != 0))); | ||
| 462 | group.Add(AttributeIfTrue("NonVital", ((attributes & Group6Symbol.SymbolAttributes.NonVital) != 0))); | ||
| 463 | group.Add(AttributeIfTrue("RemoveComment", ((attributes & Group6Symbol.SymbolAttributes.RemoveComment) != 0))); | ||
| 464 | } | ||
| 465 | else | ||
| 466 | { | ||
| 467 | this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Group_", groupId, "Group")); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | |||
| 473 | /// <summary> | ||
| 474 | /// Decompile the GroupGroup6 table. | ||
| 475 | /// </summary> | ||
| 476 | /// <param name="table">The table to decompile.</param> | ||
| 477 | private void DecompileGroupGroup6Table(Table table) | ||
| 478 | { | ||
| 479 | foreach (var row in table.Rows) | ||
| 480 | { | ||
| 481 | var childId = row.FieldAsString(1); | ||
| 482 | if (this.DecompilerHelper.TryGetIndexedElement("Group", childId, out var group)) | ||
| 483 | { | ||
| 484 | group.Add(new XElement(UtilConstants.GroupRefName, new XAttribute("Id", row.FieldAsString(0)))); | ||
| 485 | } | ||
| 486 | else | ||
| 487 | { | ||
| 488 | this.Messaging.Write(WarningMessages.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(), "Parent_", childId, "Group")); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | } | ||
| 442 | 492 | ||
| 443 | /// <summary> | 493 | /// <summary> |
| 444 | /// Decompile the WixInternetShortcut table. | 494 | /// Decompile the WixInternetShortcut table. |
diff --git a/src/ext/Util/wixext/UtilTableDefinitions.cs b/src/ext/Util/wixext/UtilTableDefinitions.cs index baa1d25b..908b7eea 100644 --- a/src/ext/Util/wixext/UtilTableDefinitions.cs +++ b/src/ext/Util/wixext/UtilTableDefinitions.cs | |||
| @@ -105,6 +105,29 @@ namespace WixToolset.Util | |||
| 105 | symbolIdIsPrimaryKey: true | 105 | symbolIdIsPrimaryKey: true |
| 106 | ); | 106 | ); |
| 107 | 107 | ||
| 108 | public static readonly TableDefinition Wix6Group = new TableDefinition( | ||
| 109 | "Wix6Group", | ||
| 110 | UtilSymbolDefinitions.Group6, | ||
| 111 | new[] | ||
| 112 | { | ||
| 113 | new ColumnDefinition("Group_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4Group", keyColumn: 1, description: "Primary key, non-localized token", modularizeType: ColumnModularizeType.Column), | ||
| 114 | new ColumnDefinition("Comment", ColumnType.String, 255, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Group comment", modularizeType: ColumnModularizeType.Property), | ||
| 115 | new ColumnDefinition("Attributes", ColumnType.Number, 4, primaryKey: false, nullable: true, ColumnCategory.Unknown, minValue: 0, maxValue: 65535, description: "Attributes describing how to create the group"), | ||
| 116 | }, | ||
| 117 | symbolIdIsPrimaryKey: false | ||
| 118 | ); | ||
| 119 | |||
| 120 | public static readonly TableDefinition Wix6GroupGroup = new TableDefinition( | ||
| 121 | "Wix6GroupGroup", | ||
| 122 | UtilSymbolDefinitions.GroupGroup, | ||
| 123 | new[] | ||
| 124 | { | ||
| 125 | new ColumnDefinition("Parent_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4Group", keyColumn: 1, description: "Parent Group", modularizeType: ColumnModularizeType.Column), | ||
| 126 | new ColumnDefinition("Child_", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, keyTable: "Wix4Group", keyColumn: 1, description: "Child Group, a member of the Parent Group", modularizeType: ColumnModularizeType.Column), | ||
| 127 | }, | ||
| 128 | symbolIdIsPrimaryKey: false | ||
| 129 | ); | ||
| 130 | |||
| 108 | public static readonly TableDefinition Wix4InternetShortcut = new TableDefinition( | 131 | public static readonly TableDefinition Wix4InternetShortcut = new TableDefinition( |
| 109 | "Wix4InternetShortcut", | 132 | "Wix4InternetShortcut", |
| 110 | UtilSymbolDefinitions.WixInternetShortcut, | 133 | UtilSymbolDefinitions.WixInternetShortcut, |
| @@ -302,6 +325,8 @@ namespace WixToolset.Util | |||
| 302 | Wix4FileShare, | 325 | Wix4FileShare, |
| 303 | Wix4FileSharePermissions, | 326 | Wix4FileSharePermissions, |
| 304 | Wix4Group, | 327 | Wix4Group, |
| 328 | Wix6Group, | ||
| 329 | Wix6GroupGroup, | ||
| 305 | Wix4InternetShortcut, | 330 | Wix4InternetShortcut, |
| 306 | Wix4PerformanceCategory, | 331 | Wix4PerformanceCategory, |
| 307 | Wix4Perfmon, | 332 | Wix4Perfmon, |
diff --git a/src/ext/Util/wixlib/UtilExtension.wxs b/src/ext/Util/wixlib/UtilExtension.wxs index 7bc50c96..bc0f651d 100644 --- a/src/ext/Util/wixlib/UtilExtension.wxs +++ b/src/ext/Util/wixlib/UtilExtension.wxs | |||
| @@ -15,6 +15,14 @@ | |||
| 15 | </Fragment> | 15 | </Fragment> |
| 16 | 16 | ||
| 17 | <Fragment> | 17 | <Fragment> |
| 18 | <UI Id="ConfigureGroupsErrorText"> | ||
| 19 | <Error Id="$(var.msierrGRPFailedGroupCreate)" Message="!(loc.msierrGRPFailedGroupCreate)" /> | ||
| 20 | <Error Id="$(var.msierrGRPFailedGroupGroupAdd)" Message="!(loc.msierrGRPFailedGroupGroupAdd)" /> | ||
| 21 | <Error Id="$(var.msierrGRPFailedGroupCreateExists)" Message="!(loc.msierrGRPFailedGroupCreateExists)" /> | ||
| 22 | </UI> | ||
| 23 | </Fragment> | ||
| 24 | |||
| 25 | <Fragment> | ||
| 18 | <UI Id="ConfigureSmbErrorsText"> | 26 | <UI Id="ConfigureSmbErrorsText"> |
| 19 | <Error Id="$(var.msierrSMBFailedCreate)" Message="!(loc.msierrSMBFailedCreate)" /> | 27 | <Error Id="$(var.msierrSMBFailedCreate)" Message="!(loc.msierrSMBFailedCreate)" /> |
| 20 | <Error Id="$(var.msierrSMBFailedDrop)" Message="!(loc.msierrSMBFailedDrop)" /> | 28 | <Error Id="$(var.msierrSMBFailedDrop)" Message="!(loc.msierrSMBFailedDrop)" /> |
diff --git a/src/ext/Util/wixlib/UtilExtension_Platform.wxi b/src/ext/Util/wixlib/UtilExtension_Platform.wxi index 690c76c5..df53c7d4 100644 --- a/src/ext/Util/wixlib/UtilExtension_Platform.wxi +++ b/src/ext/Util/wixlib/UtilExtension_Platform.wxi | |||
| @@ -133,6 +133,20 @@ | |||
| 133 | </Fragment> | 133 | </Fragment> |
| 134 | 134 | ||
| 135 | <Fragment> | 135 | <Fragment> |
| 136 | <UIRef Id="ConfigureGroupsErrorText" /> | ||
| 137 | |||
| 138 | <CustomAction Id="$(var.Prefix)ConfigureGroups$(var.Suffix)" DllEntry="ConfigureGroups" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> | ||
| 139 | <CustomAction Id="$(var.Prefix)CreateGroup$(var.Suffix)" DllEntry="CreateGroup" Impersonate="no" Execute="deferred" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> | ||
| 140 | <CustomAction Id="$(var.Prefix)CreateGroupRollback$(var.Suffix)" DllEntry="CreateGroupRollback" Impersonate="no" Execute="rollback" Return="check" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> | ||
| 141 | <!-- RemoveGroup is a type commit action because it is not possible to rollback the removal of a group --> | ||
| 142 | <CustomAction Id="$(var.Prefix)RemoveGroup$(var.Suffix)" DllEntry="RemoveGroup" Impersonate="no" Execute="commit" Return="ignore" HideTarget="yes" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> | ||
| 143 | |||
| 144 | <InstallExecuteSequence> | ||
| 145 | <Custom Action="virtual $(var.Prefix)ConfigureGroups$(var.Suffix)" Before="InstallFiles" Condition="VersionNT > 400" /> | ||
| 146 | </InstallExecuteSequence> | ||
| 147 | </Fragment> | ||
| 148 | |||
| 149 | <Fragment> | ||
| 136 | <UIRef Id="ConfigureUsersErrorText" /> | 150 | <UIRef Id="ConfigureUsersErrorText" /> |
| 137 | 151 | ||
| 138 | <CustomAction Id="$(var.Prefix)ConfigureUsers$(var.Suffix)" DllEntry="ConfigureUsers" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> | 152 | <CustomAction Id="$(var.Prefix)ConfigureUsers$(var.Suffix)" DllEntry="ConfigureUsers" Execute="immediate" Return="check" SuppressModularization="yes" BinaryRef="$(var.Prefix)UtilCA$(var.Suffix)" /> |
diff --git a/src/ext/Util/wixlib/de-de.wxl b/src/ext/Util/wixlib/de-de.wxl index 4f9dcfdd..37d5e620 100644 --- a/src/ext/Util/wixlib/de-de.wxl +++ b/src/ext/Util/wixlib/de-de.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Konnte den Benutzer nicht gewähren 'Anmelden als ein Service' Rechte. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Konnte den Benutzer nicht gewähren 'Anmelden als ein Service' Rechte. ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Konnte den Benutzer nicht anlegen, da er bereits existierte. ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Konnte den Benutzer nicht anlegen, da er bereits existierte. ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="Könnte die Gruppe nicht anlegen. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="Könnte die Gruppe nicht zur Gruppe hinzufügen. ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="Könnte die Gruppe nicht anlegen, da er bereits existierte. ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Konnte Netzwerkfreigabe nicht anlegen. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Konnte Netzwerkfreigabe nicht anlegen. ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Konnte Netzwerkfreigabe nicht entfernen. ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Konnte Netzwerkfreigabe nicht entfernen. ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/Util/wixlib/en-us.wxl b/src/ext/Util/wixlib/en-us.wxl index 8fe7a75e..a0ae0265 100644 --- a/src/ext/Util/wixlib/en-us.wxl +++ b/src/ext/Util/wixlib/en-us.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Failed to grant 'logon as service' rights to user. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Failed to grant 'logon as service' rights to user. ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Failed to create user because it already exists. ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Failed to create user because it already exists. ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="Failed to create group. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="Failed to add group to group. ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="Failed to create group because it already exists. ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Failed to create network share. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Failed to create network share. ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Failed to drop network share. ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Failed to drop network share. ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/Util/wixlib/es-es.wxl b/src/ext/Util/wixlib/es-es.wxl index 7b87ae50..3756027a 100644 --- a/src/ext/Util/wixlib/es-es.wxl +++ b/src/ext/Util/wixlib/es-es.wxl | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="No se pudieron otorgar derechos de 'iniciar sesión como servicio' al usuario. ([2] [3] [4] [5])" /> | 7 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="No se pudieron otorgar derechos de 'iniciar sesión como servicio' al usuario. ([2] [3] [4] [5])" /> |
| 8 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La creación del usuario ha fracasado porque ya existe. ([2] [3] [4] [5])" /> |
| 9 | 9 | ||
| 10 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La creación del grupo ha fracasado. ([2] [3] [4] [5])" /> | ||
| 11 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="El aditamento del grupo al grupo ha fracasado. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La creación del grupo ha fracasado porque ya existe. ([2] [3] [4] [5])" /> | ||
| 13 | |||
| 10 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La creación de la red compartida ha fracasado. ([2] [3] [4] [5])" /> | 14 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La creación de la red compartida ha fracasado. ([2] [3] [4] [5])" /> |
| 11 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="La eliminación de la red compartida ha fracasado. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="La eliminación de la red compartida ha fracasado. ([2] [3] [4] [5])" /> |
| 12 | 16 | ||
diff --git a/src/ext/Util/wixlib/fr-fr.wxl b/src/ext/Util/wixlib/fr-fr.wxl index 54ff5162..4b9aa9ad 100644 --- a/src/ext/Util/wixlib/fr-fr.wxl +++ b/src/ext/Util/wixlib/fr-fr.wxl | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Échec de l'octroi des droits de « connexion en tant que service » à l'utilisateur. ([2] [3] [4] [5])" /> | 7 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Échec de l'octroi des droits de « connexion en tant que service » à l'utilisateur. ([2] [3] [4] [5])" /> |
| 8 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="La création de l'utilisateur a échoué car il existe dejà. ([2] [3] [4] [5])" /> |
| 9 | 9 | ||
| 10 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="La création du groupe a échoué. ([2] [3] [4] [5])" /> | ||
| 11 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="L'ajout du groupe au groupe a échoué. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="La création du groupe a échoué car il existe dejà. ([2] [3] [4] [5])" /> | ||
| 13 | |||
| 10 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La création du partage reseau a échoué. ([2] [3] [4] [5])" /> | 14 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="La création du partage reseau a échoué. ([2] [3] [4] [5])" /> |
| 11 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="La suppression du partage reseau a échoué. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="La suppression du partage reseau a échoué. ([2] [3] [4] [5])" /> |
| 12 | 16 | ||
diff --git a/src/ext/Util/wixlib/it-it.wxl b/src/ext/Util/wixlib/it-it.wxl index 350cfe9e..9d41aad4 100644 --- a/src/ext/Util/wixlib/it-it.wxl +++ b/src/ext/Util/wixlib/it-it.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Impossibile concedere i 'accedere come servizio' diritti all'utente. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Impossibile concedere i 'accedere come servizio' diritti all'utente. ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Impossibile creare l'utente perchè già esistente. ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Impossibile creare l'utente perchè già esistente. ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="Impossibile creare il gruppo. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="Impossibile aggiungere il gruppo al gruppo. ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="Impossibile creare il gruppo perchè già esistente. ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Impossibile creare la risorsa di rete. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Impossibile creare la risorsa di rete. ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Impossibile eliminare la risorsa di rete. ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Impossibile eliminare la risorsa di rete. ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/Util/wixlib/ja-jp.wxl b/src/ext/Util/wixlib/ja-jp.wxl index 0a32f93c..64f3a36d 100644 --- a/src/ext/Util/wixlib/ja-jp.wxl +++ b/src/ext/Util/wixlib/ja-jp.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="ユーザーに「サービスとしてログオン」権限を付与できませんでした。 ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="ユーザーに「サービスとしてログオン」権限を付与できませんでした。 ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="ユーザーが既に存在するため作成できませんでした。 ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="ユーザーが既に存在するため作成できませんでした。 ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="グループの作成に失敗しました。 ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="グループをグループに追加でいませんでした。 ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="グループがすでに存在するため、作成できませんでした。 ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="ネットワーク共有の作成に失敗しました。 ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="ネットワーク共有の作成に失敗しました。 ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="ネットワーク共有の削除に失敗しました。 ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="ネットワーク共有の削除に失敗しました。 ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/Util/wixlib/nl-nl.wxl b/src/ext/Util/wixlib/nl-nl.wxl index 0fa25069..d1728ca6 100644 --- a/src/ext/Util/wixlib/nl-nl.wxl +++ b/src/ext/Util/wixlib/nl-nl.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="De gebruiker kon niet worden rechten verlenen 'aanmelden als service'. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="De gebruiker kon niet worden rechten verlenen 'aanmelden als service'. ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="De gebruiker kon niet worden aangemaakt omdat hij al bestond. ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="De gebruiker kon niet worden aangemaakt omdat hij al bestond. ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="De groep kan niet worden aangemaakt. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="De groep kan niet worden toegevoegd. ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="De groep kan niet worden aangemaakt omdat hij al bestond. ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Netwerk delen kon niet worden aangemaakt. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Netwerk delen kon niet worden aangemaakt. ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Netwerk delen kon niet worden verwijderd. ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Netwerk delen kon niet worden verwijderd. ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/Util/wixlib/pt-br.wxl b/src/ext/Util/wixlib/pt-br.wxl index 7e841698..a1c50e53 100644 --- a/src/ext/Util/wixlib/pt-br.wxl +++ b/src/ext/Util/wixlib/pt-br.wxl | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Não foi possível conceder ao usuário direitos de 'fazer logon como serviço'. ([2] [3] [4] [5])" /> | 8 | <String Id="msierrUSRFailedGrantLogonAsService" Overridable="yes" Value="Não foi possível conceder ao usuário direitos de 'fazer logon como serviço'. ([2] [3] [4] [5])" /> |
| 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Falha ao criar o usuário, porque ele já existe. ([2] [3] [4] [5])" /> | 9 | <String Id="msierrUSRFailedUserCreateExists" Overridable="yes" Value="Falha ao criar o usuário, porque ele já existe. ([2] [3] [4] [5])" /> |
| 10 | 10 | ||
| 11 | <String Id="msierrGRPFailedGroupCreate" Overridable="yes" Value="Falha ao criar grupo. ([2] [3] [4] [5])" /> | ||
| 12 | <String Id="msierrGRPFailedGroupGroupAdd" Overridable="yes" Value="Falha ao adicionar o grupo ao grupo. ([2] [3] [4] [5])" /> | ||
| 13 | <String Id="msierrGRPFailedGroupCreateExists" Overridable="yes" Value="Falha ao criar o grupo, porque ele já existe. ([2] [3] [4] [5])" /> | ||
| 14 | |||
| 11 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Falha ao criar o compartilhamento de rede. ([2] [3] [4] [5])" /> | 15 | <String Id="msierrSMBFailedCreate" Overridable="yes" Value="Falha ao criar o compartilhamento de rede. ([2] [3] [4] [5])" /> |
| 12 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Falha ao cair compartilhamento de rede. ([2] [3] [4] [5])" /> | 16 | <String Id="msierrSMBFailedDrop" Overridable="yes" Value="Falha ao cair compartilhamento de rede. ([2] [3] [4] [5])" /> |
| 13 | 17 | ||
diff --git a/src/ext/caerr.wxi b/src/ext/caerr.wxi index ff7ec121..a6f18f0c 100644 --- a/src/ext/caerr.wxi +++ b/src/ext/caerr.wxi | |||
| @@ -64,6 +64,9 @@ | |||
| 64 | <?define msierrUSRFailedUserGroupAdd = 26403?> | 64 | <?define msierrUSRFailedUserGroupAdd = 26403?> |
| 65 | <?define msierrUSRFailedUserCreateExists = 26404?> | 65 | <?define msierrUSRFailedUserCreateExists = 26404?> |
| 66 | <?define msierrUSRFailedGrantLogonAsService = 26405?> | 66 | <?define msierrUSRFailedGrantLogonAsService = 26405?> |
| 67 | <?define msierrGRPFailedGroupCreate = 26421?> | ||
| 68 | <?define msierrGRPFailedGroupGroupAdd = 26422?> | ||
| 69 | <?define msierrGRPFailedGroupCreateExists = 26423?> | ||
| 67 | <?define msierrDependencyMissingDependencies = 26451?> | 70 | <?define msierrDependencyMissingDependencies = 26451?> |
| 68 | <?define msierrDependencyHasDependents = 26452?> | 71 | <?define msierrDependencyHasDependents = 26452?> |
| 69 | <?define msierrDotNetRuntimeRequired = 27000?> | 72 | <?define msierrDotNetRuntimeRequired = 27000?> |
diff --git a/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h b/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h index f149fb31..d4bb991c 100644 --- a/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h +++ b/src/libs/wcautil/WixToolset.WcaUtil/custommsierrors.h | |||
| @@ -87,6 +87,9 @@ | |||
| 87 | #define msierrUSRFailedUserCreateExists 26404 | 87 | #define msierrUSRFailedUserCreateExists 26404 |
| 88 | #define msierrUSRFailedGrantLogonAsService 26405 | 88 | #define msierrUSRFailedGrantLogonAsService 26405 |
| 89 | 89 | ||
| 90 | #define msierrGRPFailedGroupCreate 26421 | ||
| 91 | #define msierrGRPFailedGroupCreateExists 26422 | ||
| 92 | |||
| 90 | #define msierrDependencyMissingDependencies 26451 | 93 | #define msierrDependencyMissingDependencies 26451 |
| 91 | #define msierrDependencyHasDependents 26452 | 94 | #define msierrDependencyHasDependents 26452 |
| 92 | 95 | ||
diff --git a/src/test/burn/WixTestTools/UserGroupVerifier.cs b/src/test/burn/WixTestTools/UserGroupVerifier.cs new file mode 100644 index 00000000..2f874057 --- /dev/null +++ b/src/test/burn/WixTestTools/UserGroupVerifier.cs | |||
| @@ -0,0 +1,198 @@ | |||
| 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 | namespace WixTestTools | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Text; | ||
| 7 | using System.DirectoryServices; | ||
| 8 | using System.DirectoryServices.AccountManagement; | ||
| 9 | using System.Security.Principal; | ||
| 10 | using Xunit; | ||
| 11 | |||
| 12 | /// <summary> | ||
| 13 | /// Contains methods for User Group verification | ||
| 14 | /// </summary> | ||
| 15 | public static class UserGroupVerifier | ||
| 16 | { | ||
| 17 | /// <summary> | ||
| 18 | /// Create a local group on the machine | ||
| 19 | /// </summary> | ||
| 20 | /// <param name="groupName"></param> | ||
| 21 | /// <remarks>Has to be run as an Admin</remarks> | ||
| 22 | public static void CreateLocalGroup(string groupName) | ||
| 23 | { | ||
| 24 | DeleteLocalGroup(groupName); | ||
| 25 | GroupPrincipal newGroup = new GroupPrincipal(new PrincipalContext(ContextType.Machine)); | ||
| 26 | newGroup.Name = groupName; | ||
| 27 | newGroup.Description = String.Empty; | ||
| 28 | newGroup.Save(); | ||
| 29 | } | ||
| 30 | |||
| 31 | /// <summary> | ||
| 32 | /// Deletes a local gorup from the machine | ||
| 33 | /// </summary> | ||
| 34 | /// <param name="groupName">group name to delete</param> | ||
| 35 | /// <remarks>Has to be run as an Admin</remarks> | ||
| 36 | public static void DeleteLocalGroup(string groupName) | ||
| 37 | { | ||
| 38 | GroupPrincipal newGroup = GetGroup(String.Empty, groupName); | ||
| 39 | if (null != newGroup) | ||
| 40 | { | ||
| 41 | newGroup.Delete(); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | /// <summary> | ||
| 46 | /// Verifies that a group exists or not | ||
| 47 | /// </summary> | ||
| 48 | /// <param name="domainName">domain name for the group, empty for local groups</param> | ||
| 49 | /// <param name="groupName">the group name</param> | ||
| 50 | public static bool GroupExists(string domainName, string groupName) | ||
| 51 | { | ||
| 52 | GroupPrincipal group = GetGroup(domainName, groupName); | ||
| 53 | |||
| 54 | return null != group; | ||
| 55 | } | ||
| 56 | |||
| 57 | /// <summary> | ||
| 58 | /// Sets the group comment for a given group | ||
| 59 | /// </summary> | ||
| 60 | /// <param name="domainName">domain name for the group, empty for local users</param> | ||
| 61 | /// <param name="groupName">the group name</param> | ||
| 62 | /// <param name="comment">comment to be set for the group</param> | ||
| 63 | public static void SetGroupComment(string domainName, string groupName, string comment) | ||
| 64 | { | ||
| 65 | GroupPrincipal group = GetGroup(domainName, groupName); | ||
| 66 | |||
| 67 | Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", groupName, domainName)); | ||
| 68 | |||
| 69 | var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry; | ||
| 70 | Assert.False(null == directoryEntry); | ||
| 71 | directoryEntry.Properties["Description"].Value = comment; | ||
| 72 | group.Save(); | ||
| 73 | } | ||
| 74 | |||
| 75 | /// <summary> | ||
| 76 | /// Adds the specified group to the specified local group | ||
| 77 | /// </summary> | ||
| 78 | /// <param name="memberName">Member to add</param> | ||
| 79 | /// <param name="groupName">Group to add too</param> | ||
| 80 | public static void AddGroupToGroup(string memberName, string groupName) | ||
| 81 | { | ||
| 82 | DirectoryEntry localMachine; | ||
| 83 | DirectoryEntry localGroup; | ||
| 84 | |||
| 85 | localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString()); | ||
| 86 | localGroup = localMachine.Children.Find(groupName, "group"); | ||
| 87 | Assert.False(null == localGroup, String.Format("Group '{0}' was not found.", groupName)); | ||
| 88 | DirectoryEntry group = FindActiveDirectoryGroup(memberName); | ||
| 89 | localGroup.Invoke("Add", new object[] { group.Path.ToString() }); | ||
| 90 | } | ||
| 91 | |||
| 92 | /// <summary> | ||
| 93 | /// Find the specified group in AD | ||
| 94 | /// </summary> | ||
| 95 | /// <param name="groupName">group name to lookup</param> | ||
| 96 | /// <returns>DirectoryEntry of the group</returns> | ||
| 97 | private static DirectoryEntry FindActiveDirectoryGroup(string groupName) | ||
| 98 | { | ||
| 99 | var mLocalMachine = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString()); | ||
| 100 | var mLocalEntries = mLocalMachine.Children; | ||
| 101 | |||
| 102 | var theGroup = mLocalEntries.Find(groupName); | ||
| 103 | return theGroup; | ||
| 104 | } | ||
| 105 | |||
| 106 | /// <summary> | ||
| 107 | /// Verifies the group comment for a given group | ||
| 108 | /// </summary> | ||
| 109 | /// <param name="domainName">domain name for the group, empty for local users</param> | ||
| 110 | /// <param name="groupName">the group name</param> | ||
| 111 | /// <param name="comment">the comment to be verified</param> | ||
| 112 | public static void VerifyGroupComment(string domainName, string groupName, string comment) | ||
| 113 | { | ||
| 114 | GroupPrincipal group = GetGroup(domainName, groupName); | ||
| 115 | |||
| 116 | Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", groupName, domainName)); | ||
| 117 | |||
| 118 | var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry; | ||
| 119 | Assert.False(null == directoryEntry); | ||
| 120 | Assert.True(comment == (string)(directoryEntry.Properties["Description"].Value)); | ||
| 121 | } | ||
| 122 | |||
| 123 | /// <summary> | ||
| 124 | /// Verify that a given group is member of a local group | ||
| 125 | /// </summary> | ||
| 126 | /// <param name="domainName">domain name for the group, empty for local groups</param> | ||
| 127 | /// <param name="memberName">the member name</param> | ||
| 128 | /// <param name="groupNames">list of groups to check for membership</param> | ||
| 129 | public static void VerifyIsMemberOf(string domainName, string memberName, params string[] groupNames) | ||
| 130 | { | ||
| 131 | IsMemberOf(domainName, memberName, true, groupNames); | ||
| 132 | } | ||
| 133 | |||
| 134 | /// <summary> | ||
| 135 | /// Verify that a given group is NOT member of a local group | ||
| 136 | /// </summary> | ||
| 137 | /// <param name="domainName">domain name for the group, empty for local groups</param> | ||
| 138 | /// <param name="memberName">the member name</param> | ||
| 139 | /// <param name="groupNames">list of groups to check for membership</param> | ||
| 140 | public static void VerifyIsNotMemberOf(string domainName, string memberName, params string[] groupNames) | ||
| 141 | { | ||
| 142 | IsMemberOf(domainName, memberName, false, groupNames); | ||
| 143 | } | ||
| 144 | |||
| 145 | /// <summary> | ||
| 146 | /// Verify that a given user is member of a local group | ||
| 147 | /// </summary> | ||
| 148 | /// <param name="domainName">domain name for the group, empty for local groups</param> | ||
| 149 | /// <param name="memberName">the member name</param> | ||
| 150 | /// <param name="shouldBeMember">whether the group is expected to be a member of the groups or not</param> | ||
| 151 | /// <param name="groupNames">list of groups to check for membership</param> | ||
| 152 | private static void IsMemberOf(string domainName, string memberName, bool shouldBeMember, params string[] groupNames) | ||
| 153 | { | ||
| 154 | GroupPrincipal group = GetGroup(domainName, memberName); | ||
| 155 | Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", memberName, domainName)); | ||
| 156 | |||
| 157 | bool missedAGroup = false; | ||
| 158 | string message = String.Empty; | ||
| 159 | foreach (string groupName in groupNames) | ||
| 160 | { | ||
| 161 | try | ||
| 162 | { | ||
| 163 | bool found = group.IsMemberOf(new PrincipalContext(ContextType.Machine), IdentityType.Name, groupName); | ||
| 164 | if (found != shouldBeMember) | ||
| 165 | { | ||
| 166 | missedAGroup = true; | ||
| 167 | message += String.Format("Group '{0}/{1}' is {2} a member of local group '{3}'. \r\n", domainName, memberName, found ? String.Empty : "NOT", groupName); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | catch (System.DirectoryServices.AccountManagement.PrincipalOperationException) | ||
| 171 | { | ||
| 172 | missedAGroup = true; | ||
| 173 | message += String.Format("Local group '{0}' was not found. \r\n", groupName); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | Assert.False(missedAGroup, message); | ||
| 177 | } | ||
| 178 | |||
| 179 | /// <summary> | ||
| 180 | /// Returns the GroupPrincipal object for a given group | ||
| 181 | /// </summary> | ||
| 182 | /// <param name="domainName">Domain name to look under, if Empty the LocalMachine is assumed as the domain</param> | ||
| 183 | /// <param name="groupName"></param> | ||
| 184 | /// <returns>UserPrincipal Object for the group if found, or null other wise</returns> | ||
| 185 | private static GroupPrincipal GetGroup(string domainName, string groupName) | ||
| 186 | { | ||
| 187 | if (String.IsNullOrEmpty(domainName)) | ||
| 188 | { | ||
| 189 | return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), IdentityType.Name, groupName); | ||
| 190 | } | ||
| 191 | else | ||
| 192 | { | ||
| 193 | return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), IdentityType.Name, groupName); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/ProductA.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/ProductA.wixproj new file mode 100644 index 00000000..3895b853 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/ProductA.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>{A3E0B539-63F9-4B43-9E34-F33AE1C6E06D}</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> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/product.wxs new file mode 100644 index 00000000..e3c143e6 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductA/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 | |||
| 10 | <Property Id="TEMPDOMAIN" Secure="yes" /> | ||
| 11 | <Property Id="TEMPGROUPNAME" Secure="yes" /> | ||
| 12 | </Fragment> | ||
| 13 | |||
| 14 | <Fragment> | ||
| 15 | <Component Id="Component1" Guid="09624A9A-4BBC-4126-BBF9-0713C5217DB1" Directory="INSTALLFOLDER"> | ||
| 16 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 17 | |||
| 18 | <util:Group Id="TEST_GROUP1" Name="testName1" Comment="Group1" CreateGroup="yes" RemoveOnUninstall="yes" /> | ||
| 19 | |||
| 20 | <util:Group Id="TEST_GROUP2" Name="testName2" Comment="Group2" RemoveOnUninstall="no" UpdateIfExists="yes" /> | ||
| 21 | |||
| 22 | <util:Group Id="TEST_GROUP3" Name="testName3" Comment="Group3" CreateGroup="no" /> | ||
| 23 | </Component> | ||
| 24 | </Fragment> | ||
| 25 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/ProductAddCommentToExistingGroup.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/ProductAddCommentToExistingGroup.wixproj new file mode 100644 index 00000000..5938e525 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/ProductAddCommentToExistingGroup.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/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/product.wxs new file mode 100644 index 00000000..e0170746 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductAddCommentToExistingGroup/product.wxs | |||
| @@ -0,0 +1,23 @@ | |||
| 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:Group Id="TEST_GROUP1" | ||
| 16 | Name="testName1" | ||
| 17 | CreateGroup="yes" | ||
| 18 | UpdateIfExists="yes" | ||
| 19 | RemoveOnUninstall="yes" | ||
| 20 | Comment="testComment1"/> | ||
| 21 | </Component> | ||
| 22 | </Fragment> | ||
| 23 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentDelete/ProductCommentDelete.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentDelete/ProductCommentDelete.wixproj new file mode 100644 index 00000000..63bb2370 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/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/UtilExtensionGroupTests/ProductCommentDelete/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentDelete/product.wxs new file mode 100644 index 00000000..d1824890 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/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:Group Id="TEST_GROUP1" Name="testName1" UpdateIfExists="yes" RemoveOnUninstall="yes" RemoveComment="yes"/> | ||
| 16 | </Component> | ||
| 17 | </Fragment> | ||
| 18 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/ProductCommentFail.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/ProductCommentFail.wixproj new file mode 100644 index 00000000..66f308ae --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/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/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductCommentFail/product_fail.wxs new file mode 100644 index 00000000..29b908da --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/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="Wix4ConfigureGroups_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:Group Id="TEST_GROUP1" Name="testName1" CreateGroup="yes" RemoveOnUninstall="yes" Comment="testComment1"/> | ||
| 20 | </Component> | ||
| 21 | </Fragment> | ||
| 22 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/ProductFail.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/ProductFail.wixproj new file mode 100644 index 00000000..e2fe3aa8 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/ProductFail.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>{91D27DAC-04C1-4160-914E-343676D36CAA}</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> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs new file mode 100644 index 00000000..fb35bc1e --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFail/product_fail.wxs | |||
| @@ -0,0 +1,29 @@ | |||
| 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 | <Property Id="TEMPDOMAIN" Secure="yes" /> | ||
| 11 | <Property Id="TEMPUSERNAME" Secure="yes" /> | ||
| 12 | |||
| 13 | <InstallExecuteSequence> | ||
| 14 | <Custom Action="CaFail" After="Wix4ConfigureGroups_X86" /> | ||
| 15 | </InstallExecuteSequence> | ||
| 16 | </Fragment> | ||
| 17 | |||
| 18 | <Fragment> | ||
| 19 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 20 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 21 | |||
| 22 | <util:Group Id="TEST_GROUP1" Name="testName1" /> | ||
| 23 | |||
| 24 | <util:Group Id="TEST_GROUP2" Name="testName2" RemoveOnUninstall="no" UpdateIfExists="yes" /> | ||
| 25 | |||
| 26 | <util:Group Id="TEST_GROUP3" Name="testName3" CreateGroup="no" /> | ||
| 27 | </Component> | ||
| 28 | </Fragment> | ||
| 29 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/FailIfExists.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/FailIfExists.wxs new file mode 100644 index 00000000..00f8e12d --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/FailIfExists.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:Group Id="TEST_USER4" Name="existinggroup" FailIfExists="yes" RemoveOnUninstall="yes" /> | ||
| 16 | </Component> | ||
| 17 | </Fragment> | ||
| 18 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/ProductFailIfExists.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/ProductFailIfExists.wixproj new file mode 100644 index 00000000..9e1a836f --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductFailIfExists/ProductFailIfExists.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>{BC803822-929E-47DA-AB3A-3A62EEEA2BFB}</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> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/ProductNestedGroups.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/ProductNestedGroups.wixproj new file mode 100644 index 00000000..3b2e3942 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/ProductNestedGroups.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>{8B6C2900-44C4-42C9-879F-82F551B10C15}</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/UtilExtensionGroupTests/ProductNestedGroups/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs new file mode 100644 index 00000000..191d605c --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNestedGroups/product.wxs | |||
| @@ -0,0 +1,33 @@ | |||
| 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 | <Property Id="TEMPDOMAIN" Secure="yes" /> | ||
| 11 | <Property Id="TEMPGROUPNAME" Secure="yes" /> | ||
| 12 | </Fragment> | ||
| 13 | |||
| 14 | <Fragment> | ||
| 15 | <util:Group Id="ADMIN" Name="Administrators" > | ||
| 16 | <util:GroupRef Id="TEST_GROUP1" /> | ||
| 17 | <util:GroupRef Id="TEST_GROUP2" /> | ||
| 18 | </util:Group> | ||
| 19 | <util:Group Id="POWER_USERS" Name="Power Users" > | ||
| 20 | <util:GroupRef Id="TEST_GROUP1" /> | ||
| 21 | </util:Group> | ||
| 22 | |||
| 23 | <Component Id="Component1" Guid="09624A9A-4BBC-4126-BBF9-0713C5217DB1" Directory="INSTALLFOLDER"> | ||
| 24 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 25 | |||
| 26 | <util:Group Id="TEST_GROUP1" Name="testName1" Comment="Group1" CreateGroup="yes" RemoveOnUninstall="yes" /> | ||
| 27 | |||
| 28 | <util:Group Id="TEST_GROUP2" Name="testName2" Comment="Group2" RemoveOnUninstall="no" UpdateIfExists="yes" /> | ||
| 29 | |||
| 30 | <util:Group Id="TEST_GROUP3" Name="testName3" Comment="Group3" /> | ||
| 31 | </Component> | ||
| 32 | </Fragment> | ||
| 33 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNewGroupWithComment/ProductNewGroupWithComment.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNewGroupWithComment/ProductNewGroupWithComment.wixproj new file mode 100644 index 00000000..aeac903a --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNewGroupWithComment/ProductNewGroupWithComment.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/UtilExtensionGroupTests/ProductNewGroupWithComment/product.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNewGroupWithComment/product.wxs new file mode 100644 index 00000000..2d012b23 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNewGroupWithComment/product.wxs | |||
| @@ -0,0 +1,23 @@ | |||
| 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:Group | ||
| 15 | Id="TEST_GROUP1" | ||
| 16 | Name="testName1" | ||
| 17 | CreateGroup="yes" | ||
| 18 | UpdateIfExists="yes" | ||
| 19 | RemoveOnUninstall="yes" | ||
| 20 | Comment="testComment1" /> | ||
| 21 | </Component> | ||
| 22 | </Fragment> | ||
| 23 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/NonVitalUserGroup.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/NonVitalUserGroup.wxs new file mode 100644 index 00000000..a834c76b --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/NonVitalUserGroup.wxs | |||
| @@ -0,0 +1,19 @@ | |||
| 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 | |||
| 13 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 14 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 15 | |||
| 16 | <util:Group Id="CurrentGroup" Name="[LogonUser]" Domain="[%USERDOMAIN]" RemoveOnUninstall="no" Vital="no" /> | ||
| 17 | </Component> | ||
| 18 | </Fragment> | ||
| 19 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/ProductNonVitalUserGroup.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/ProductNonVitalUserGroup.wixproj new file mode 100644 index 00000000..8734224d --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductNonVitalGroup/ProductNonVitalUserGroup.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>{455C8D4F-6D59-405C-AD51-0ACC7FB91A26}</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> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/ProductRestrictedDomain.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/ProductRestrictedDomain.wixproj new file mode 100644 index 00000000..e4a01a3a --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/ProductRestrictedDomain.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>{50CF526C-A862-4327-9EA3-C96AAB6FABCE}</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> \ No newline at end of file | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/RestrictedDomain.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/RestrictedDomain.wxs new file mode 100644 index 00000000..edb3387c --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductRestrictedDomain/RestrictedDomain.wxs | |||
| @@ -0,0 +1,20 @@ | |||
| 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 | <Property Id="TEMPDOMAIN" Secure="yes" /> | ||
| 11 | </Fragment> | ||
| 12 | |||
| 13 | <Fragment> | ||
| 14 | <Component Id="Component1" Guid="00030829-0000-0000-C000-000000000046" Directory="INSTALLFOLDER"> | ||
| 15 | <File Source="$(sys.SOURCEFILEPATH)" KeyPath="yes" /> | ||
| 16 | |||
| 17 | <util:Group Id="TEST_GROUP_test" Name="testName1" Domain="[TEMPDOMAIN]" /> | ||
| 18 | </Component> | ||
| 19 | </Fragment> | ||
| 20 | </Wix> | ||
diff --git a/src/test/msi/TestData/UtilExtensionGroupTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj b/src/test/msi/TestData/UtilExtensionGroupTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wixproj new file mode 100644 index 00000000..93a56216 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/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/UtilExtensionGroupTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs b/src/test/msi/TestData/UtilExtensionGroupTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs new file mode 100644 index 00000000..059ecee8 --- /dev/null +++ b/src/test/msi/TestData/UtilExtensionGroupTests/ProductWithCommandLineParameters/ProductWithCommandLineParameters.wxs | |||
| @@ -0,0 +1,19 @@ | |||
| 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:Group Id="TEST_GROUP1" | ||
| 14 | Name="[TESTPARAMETER1]" | ||
| 15 | CreateGroup="yes" | ||
| 16 | RemoveOnUninstall="yes" /> | ||
| 17 | </Component> | ||
| 18 | </Fragment> | ||
| 19 | </Wix> | ||
diff --git a/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs new file mode 100644 index 00000000..796c4ecd --- /dev/null +++ b/src/test/msi/WixToolsetTest.MsiE2E/UtilExtensionGroupTests.cs | |||
| @@ -0,0 +1,271 @@ | |||
| 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 | namespace WixToolsetTest.MsiE2E | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using WixTestTools; | ||
| 7 | using Xunit; | ||
| 8 | using Xunit.Abstractions; | ||
| 9 | |||
| 10 | public class UtilExtensionGroupTests : MsiE2ETests | ||
| 11 | { | ||
| 12 | public UtilExtensionGroupTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } | ||
| 13 | |||
| 14 | // Verify that the users specified in the authoring are created as expected. | ||
| 15 | [RuntimeFact] | ||
| 16 | public void CanInstallAndUninstallGroups() | ||
| 17 | { | ||
| 18 | UserGroupVerifier.CreateLocalGroup("testName3"); | ||
| 19 | var productA = this.CreatePackageInstaller("ProductA"); | ||
| 20 | |||
| 21 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 22 | |||
| 23 | // Validate New User Information. | ||
| 24 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName1"), String.Format("Group '{0}' was not created on Install", "testName1")); | ||
| 25 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName2"), String.Format("Group '{0}' was not created on Install", "testName2")); | ||
| 26 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName3"), String.Format("Group '{0}' was not created on Install", "testName3")); | ||
| 27 | |||
| 28 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 29 | |||
| 30 | // Verify Users marked as RemoveOnUninstall were removed. | ||
| 31 | Assert.False(UserGroupVerifier.GroupExists(String.Empty, "testName1"), String.Format("Group '{0}' was not removed on Uninstall", "testName1")); | ||
| 32 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName2"), String.Format("Group '{0}' was removed on Uninstall", "testName2")); | ||
| 33 | |||
| 34 | // clean up | ||
| 35 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 36 | UserGroupVerifier.DeleteLocalGroup("testName2"); | ||
| 37 | UserGroupVerifier.DeleteLocalGroup("testName3"); | ||
| 38 | } | ||
| 39 | |||
| 40 | // Verify the rollback action reverts all Users changes. | ||
| 41 | [RuntimeFact] | ||
| 42 | public void CanRollbackGroups() | ||
| 43 | { | ||
| 44 | UserGroupVerifier.CreateLocalGroup("testName3"); | ||
| 45 | var productFail = this.CreatePackageInstaller("ProductFail"); | ||
| 46 | |||
| 47 | // make sure the user accounts are deleted before we start | ||
| 48 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 49 | UserGroupVerifier.DeleteLocalGroup("testName2"); | ||
| 50 | |||
| 51 | productFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); | ||
| 52 | |||
| 53 | // Verify added Users were removed on rollback. | ||
| 54 | Assert.False(UserGroupVerifier.GroupExists(String.Empty, "testName1"), String.Format("Group '{0}' was not removed on Rollback", "testName1")); | ||
| 55 | Assert.False(UserGroupVerifier.GroupExists(String.Empty, "testName2"), String.Format("Group '{0}' was not removed on Rollback", "testName2")); | ||
| 56 | |||
| 57 | // clean up | ||
| 58 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 59 | UserGroupVerifier.DeleteLocalGroup("testName2"); | ||
| 60 | UserGroupVerifier.DeleteLocalGroup("testName3"); | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | // Verify that command-line parameters aer not blocked by repair switches. | ||
| 65 | // Original code signalled repair mode by using "-f ", which silently | ||
| 66 | // terminated the command-line parsing, ignoring any parameters that followed. | ||
| 67 | [RuntimeFact()] | ||
| 68 | public void CanRepairGroupsWithCommandLineParameters() | ||
| 69 | { | ||
| 70 | var arguments = new string[] | ||
| 71 | { | ||
| 72 | "TESTPARAMETER1=testName1", | ||
| 73 | }; | ||
| 74 | var productWithCommandLineParameters = this.CreatePackageInstaller("ProductWithCommandLineParameters"); | ||
| 75 | |||
| 76 | // Make sure that the user doesn't exist when we start the test. | ||
| 77 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 78 | |||
| 79 | // Install | ||
| 80 | productWithCommandLineParameters.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 81 | |||
| 82 | // Repair | ||
| 83 | productWithCommandLineParameters.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS, arguments); | ||
| 84 | |||
| 85 | // Clean up | ||
| 86 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | // Verify that the groups specified in the authoring are created as expected on repair. | ||
| 91 | [RuntimeFact()] | ||
| 92 | public void CanRepairGroups() | ||
| 93 | { | ||
| 94 | UserGroupVerifier.CreateLocalGroup("testName3"); | ||
| 95 | var productA = this.CreatePackageInstaller("ProductA"); | ||
| 96 | |||
| 97 | productA.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 98 | |||
| 99 | // Validate New User Information. | ||
| 100 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 101 | |||
| 102 | productA.RepairProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 103 | |||
| 104 | // Validate New User Information. | ||
| 105 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName1"), String.Format("User '{0}' was not installed on Repair", "testName1")); | ||
| 106 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName2"), String.Format("User '{0}' was not installed after Repair", "testName2")); | ||
| 107 | |||
| 108 | productA.UninstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 109 | |||
| 110 | // Verify Users marked as RemoveOnUninstall were removed. | ||
| 111 | Assert.False(UserGroupVerifier.GroupExists(String.Empty, "testName1"), String.Format("User '{0}' was not removed on Uninstall", "testName1")); | ||
| 112 | Assert.True(UserGroupVerifier.GroupExists(String.Empty, "testName2"), String.Format("User '{0}' was removed on Uninstall", "testName2")); | ||
| 113 | |||
| 114 | // clean up | ||
| 115 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 116 | UserGroupVerifier.DeleteLocalGroup("testName2"); | ||
| 117 | UserGroupVerifier.DeleteLocalGroup("testName3"); | ||
| 118 | } | ||
| 119 | |||
| 120 | // Verify that Installation fails if FailIfExists is set. | ||
| 121 | [RuntimeFact] | ||
| 122 | public void FailsIfGroupExists() | ||
| 123 | { | ||
| 124 | var productFailIfExists = this.CreatePackageInstaller("ProductFailIfExists"); | ||
| 125 | |||
| 126 | // Create 'existinggroup' | ||
| 127 | UserGroupVerifier.CreateLocalGroup("existinggroup"); | ||
| 128 | |||
| 129 | try | ||
| 130 | { | ||
| 131 | productFailIfExists.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); | ||
| 132 | |||
| 133 | // Verify User still exists. | ||
| 134 | bool userExists = UserGroupVerifier.GroupExists(String.Empty, "existinggroup"); | ||
| 135 | |||
| 136 | Assert.True(userExists, String.Format("Group '{0}' was removed on Rollback", "existinggroup")); | ||
| 137 | } | ||
| 138 | finally | ||
| 139 | { | ||
| 140 | // clean up | ||
| 141 | UserGroupVerifier.DeleteLocalGroup("existinggroup"); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | // Verify that a group cannot be created on a domain on which you don't have create user permission. | ||
| 146 | [RuntimeFact] | ||
| 147 | public void FailsIfRestrictedDomain() | ||
| 148 | { | ||
| 149 | var productRestrictedDomain = this.CreatePackageInstaller("ProductRestrictedDomain"); | ||
| 150 | |||
| 151 | string logFile = productRestrictedDomain.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "TEMPDOMAIN=DOESNOTEXIST"); | ||
| 152 | |||
| 153 | // Verify expected error message in the log file | ||
| 154 | Assert.True(LogVerifier.MessageInLogFile(logFile, "CreateGroup: Error 0x8007054b: failed to find Domain DOESNOTEXIST.")); | ||
| 155 | } | ||
| 156 | |||
| 157 | // Verify that a group can be created with a group comment | ||
| 158 | [RuntimeFact] | ||
| 159 | public void CanCreateNewGroupWithComment() | ||
| 160 | { | ||
| 161 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewGroupWithComment"); | ||
| 162 | |||
| 163 | productNewUserWithComment.InstallProduct(); | ||
| 164 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", "testComment1"); | ||
| 165 | |||
| 166 | // clean up | ||
| 167 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 168 | } | ||
| 169 | |||
| 170 | // Verify that a comment can be added to an existing group | ||
| 171 | [RuntimeFact] | ||
| 172 | public void CanAddCommentToExistingGroup() | ||
| 173 | { | ||
| 174 | UserGroupVerifier.CreateLocalGroup("testName1"); | ||
| 175 | var productAddCommentToExistingUser = this.CreatePackageInstaller("ProductAddCommentToExistingGroup"); | ||
| 176 | |||
| 177 | productAddCommentToExistingUser.InstallProduct(); | ||
| 178 | |||
| 179 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", "testComment1"); | ||
| 180 | |||
| 181 | // clean up | ||
| 182 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 183 | } | ||
| 184 | |||
| 185 | // Verify that a comment can be repaired for a new group | ||
| 186 | [RuntimeFact] | ||
| 187 | public void CanRepairCommentOfNewGroup() | ||
| 188 | { | ||
| 189 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewGroupWithComment"); | ||
| 190 | |||
| 191 | productNewUserWithComment.InstallProduct(); | ||
| 192 | UserGroupVerifier.SetGroupComment(String.Empty, "testName1", ""); | ||
| 193 | |||
| 194 | productNewUserWithComment.RepairProduct(); | ||
| 195 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", "testComment1"); | ||
| 196 | |||
| 197 | // clean up | ||
| 198 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 199 | } | ||
| 200 | |||
| 201 | // Verify that a comment can be changed for an existing group | ||
| 202 | [RuntimeFact] | ||
| 203 | public void CanChangeCommentOfExistingGroup() | ||
| 204 | { | ||
| 205 | UserGroupVerifier.CreateLocalGroup("testName1"); | ||
| 206 | UserGroupVerifier.SetGroupComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 207 | var productNewUserWithComment = this.CreatePackageInstaller("ProductNewGroupWithComment"); | ||
| 208 | |||
| 209 | productNewUserWithComment.InstallProduct(); | ||
| 210 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", "testComment1"); | ||
| 211 | |||
| 212 | // clean up | ||
| 213 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 214 | } | ||
| 215 | |||
| 216 | // Verify that a comment can be rolled back for an existing group | ||
| 217 | [RuntimeFact] | ||
| 218 | public void CanRollbackCommentOfExistingGroup() | ||
| 219 | { | ||
| 220 | UserGroupVerifier.CreateLocalGroup("testName1"); | ||
| 221 | UserGroupVerifier.SetGroupComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 222 | var productCommentFail = this.CreatePackageInstaller("ProductCommentFail"); | ||
| 223 | |||
| 224 | productCommentFail.InstallProduct(MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE); | ||
| 225 | |||
| 226 | // Verify that comment change was rolled back. | ||
| 227 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", "initialTestComment1"); | ||
| 228 | |||
| 229 | // clean up | ||
| 230 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 231 | } | ||
| 232 | |||
| 233 | // Verify that a comment can be deleted for an existing group | ||
| 234 | [RuntimeFact] | ||
| 235 | public void CanDeleteCommentOfExistingGroup() | ||
| 236 | { | ||
| 237 | UserGroupVerifier.CreateLocalGroup("testName1"); | ||
| 238 | UserGroupVerifier.SetGroupComment(String.Empty, "testName1", "testComment1"); | ||
| 239 | var productCommentDelete = this.CreatePackageInstaller("ProductCommentDelete"); | ||
| 240 | |||
| 241 | productCommentDelete.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 242 | |||
| 243 | // Verify that comment was removed. | ||
| 244 | UserGroupVerifier.VerifyGroupComment(String.Empty, "testName1", ""); | ||
| 245 | |||
| 246 | // clean up | ||
| 247 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 248 | } | ||
| 249 | |||
| 250 | // Verify that a comment can be deleted for an existing group | ||
| 251 | [RuntimeFact] | ||
| 252 | public void CanNestGroups() | ||
| 253 | { | ||
| 254 | var productNestedGroups = this.CreatePackageInstaller("ProductNestedGroups"); | ||
| 255 | |||
| 256 | productNestedGroups.InstallProduct(MSIExec.MSIExecReturnCode.SUCCESS); | ||
| 257 | |||
| 258 | // Verify group nested membership | ||
| 259 | UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Administrators", new string[] { "testName1", "testName2" }); | ||
| 260 | UserGroupVerifier.VerifyIsMemberOf(String.Empty, "Power Users", new string[] { "testName1" }); | ||
| 261 | |||
| 262 | UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Administrators", new string[] { "testName3" }); | ||
| 263 | UserGroupVerifier.VerifyIsNotMemberOf(String.Empty, "Power Users", new string[] { "testName2", "testName3" }); | ||
| 264 | |||
| 265 | // clean up | ||
| 266 | UserGroupVerifier.DeleteLocalGroup("testName1"); | ||
| 267 | UserGroupVerifier.DeleteLocalGroup("testName2"); | ||
| 268 | UserGroupVerifier.DeleteLocalGroup("testName3"); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | } | ||
