// 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. namespace WixTestTools { using System; using System.Text; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.Security.Principal; using Xunit; /// /// Contains methods for User Group verification /// public static class UserGroupVerifier { /// /// Create a local group on the machine /// /// /// Has to be run as an Admin public static void CreateLocalGroup(string groupName) { DeleteLocalGroup(groupName); GroupPrincipal newGroup = new GroupPrincipal(new PrincipalContext(ContextType.Machine)); newGroup.Name = groupName; newGroup.Description = String.Empty; newGroup.Save(); } /// /// Deletes a local group from the machine /// /// group name to delete /// Has to be run as an Admin public static void DeleteLocalGroup(string groupName) { GroupPrincipal newGroup = GetGroup(String.Empty, groupName); if (null != newGroup) { newGroup.Delete(); } } /// /// Verifies that a group exists or not /// /// domain name for the group, empty for local groups /// the group name public static bool GroupExists(string domainName, string groupName) { GroupPrincipal group = GetGroup(domainName, groupName); return null != group; } /// /// Sets the group comment for a given group /// /// domain name for the group, empty for local users /// the group name /// comment to be set for the group public static void SetGroupComment(string domainName, string groupName, string comment) { GroupPrincipal group = GetGroup(domainName, groupName); Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", groupName, domainName)); var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry; Assert.False(null == directoryEntry); directoryEntry.Properties["Description"].Value = comment; group.Save(); } /// /// Adds the specified group to the specified local group /// /// Member to add /// Group to add too public static void AddGroupToGroup(string memberName, string groupName) { DirectoryEntry localMachine; DirectoryEntry localGroup; localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString()); localGroup = localMachine.Children.Find(groupName, "group"); Assert.False(null == localGroup, String.Format("Group '{0}' was not found.", groupName)); DirectoryEntry group = FindActiveDirectoryGroup(memberName); localGroup.Invoke("Add", new object[] { group.Path.ToString() }); } /// /// Find the specified group in AD /// /// group name to lookup /// DirectoryEntry of the group private static DirectoryEntry FindActiveDirectoryGroup(string groupName) { var mLocalMachine = new DirectoryEntry("WinNT://" + Environment.MachineName.ToString()); var mLocalEntries = mLocalMachine.Children; var theGroup = mLocalEntries.Find(groupName); return theGroup; } /// /// Verifies the group comment for a given group /// /// domain name for the group, empty for local users /// the group name /// the comment to be verified public static void VerifyGroupComment(string domainName, string groupName, string comment) { GroupPrincipal group = GetGroup(domainName, groupName); Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", groupName, domainName)); var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry; Assert.False(null == directoryEntry); Assert.True(comment == (string)(directoryEntry.Properties["Description"].Value)); } /// /// Verify that a given group is member of a local group /// /// domain name for the group, empty for local groups /// the member name /// list of groups to check for membership public static void VerifyIsMemberOf(string domainName, string memberName, params string[] groupNames) { IsMemberOf(domainName, memberName, true, groupNames); } /// /// Verify that a given group is NOT member of a local group /// /// domain name for the group, empty for local groups /// the member name /// list of groups to check for membership public static void VerifyIsNotMemberOf(string domainName, string memberName, params string[] groupNames) { IsMemberOf(domainName, memberName, false, groupNames); } /// /// Verify that a given user is member of a local group /// /// domain name for the group, empty for local groups /// the member name /// whether the group is expected to be a member of the groups or not /// list of groups to check for membership private static void IsMemberOf(string domainName, string memberName, bool shouldBeMember, params string[] groupNames) { Principal group = GetPrincipal(domainName, memberName); Assert.False(null == group, String.Format("Group '{0}' was not found under domain '{1}'.", memberName, domainName)); bool missedAGroup = false; string message = String.Empty; foreach (string groupName in groupNames) { try { bool found = group.IsMemberOf(new PrincipalContext(ContextType.Machine), IdentityType.Name, groupName); if (found != shouldBeMember) { missedAGroup = true; message += String.Format("Group '{0}/{1}' is {2} a member of local group '{3}'. \r\n", domainName, memberName, found ? String.Empty : "NOT", groupName); } } catch (System.DirectoryServices.AccountManagement.PrincipalOperationException) { missedAGroup = true; message += String.Format("Local group '{0}' was not found. \r\n", groupName); } } Assert.False(missedAGroup, message); } /// /// Returns the GroupPrincipal object for a given group /// /// Domain name to look under, if Empty the LocalMachine is assumed as the domain /// /// UserPrincipal Object for the group if found, or null other wise private static GroupPrincipal GetGroup(string domainName, string groupName) { if (String.IsNullOrEmpty(domainName)) { return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Machine), groupName); } else { return GroupPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain,domainName), groupName); } } /// /// Returns the Principal object for a given name /// /// Domain name to look under, if Empty the LocalMachine is assumed as the domain /// /// Principal Object if found, or null other wise private static Principal GetPrincipal(string domainName, string name) { if (String.IsNullOrEmpty(domainName)) { return Principal.FindByIdentity(new PrincipalContext(ContextType.Machine), name); } else { return Principal.FindByIdentity(new PrincipalContext(ContextType.Domain, domainName), name); } } } }