Skip to content

Commit 31b2f40

Browse files
committed
Addressing CR comments
1 parent 8b50559 commit 31b2f40

File tree

12 files changed

+349
-88
lines changed

12 files changed

+349
-88
lines changed

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Commands.RemoteApp.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
</ItemGroup>
4141
<ItemGroup>
4242
<Compile Include="Collection\RemoteAppCollection.cs" />
43+
<Compile Include="Common\MockAdHelper.cs" />
4344
<Compile Include="Common\VmObjects.cs" />
4445
<Compile Include="Common\CollectionObjects.cs" />
4546
<Compile Include="Common\MockObject.cs" />
@@ -154,6 +155,8 @@
154155
<HintPath>..\..\..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
155156
</Reference>
156157
<Reference Include="System" />
158+
<Reference Include="System.DirectoryServices" />
159+
<Reference Include="System.DirectoryServices.Protocols" />
157160
<Reference Include="System.Management.Automation" />
158161
<Reference Include="System.Net" />
159162
<Reference Include="System.Net.Http" />
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.DirectoryServices;
4+
using System.Linq;
5+
using System.Management.Automation;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using Microsoft.WindowsAzure.Management.RemoteApp.Cmdlets;
9+
using Microsoft.WindowsAzure.Management.RemoteApp.Models;
10+
11+
namespace Microsoft.WindowsAzure.Commands.RemoteApp.Test.Common
12+
{
13+
class MockAdHelper : IAdHelper
14+
{
15+
internal const string CN = "cn";
16+
17+
internal IList<DirectoryEntry> entries = new List<DirectoryEntry>();
18+
19+
public class MockDirectoryEntry : DirectoryEntry
20+
{
21+
private string cn;
22+
23+
public MockDirectoryEntry(string cn)
24+
{
25+
this.cn = cn;
26+
}
27+
28+
public string MockCN
29+
{
30+
get
31+
{
32+
return cn;
33+
}
34+
}
35+
}
36+
37+
public IList<DirectoryEntry> GetVmAdEntries(string domainName, string OU, string vmNamePrefix, PSCredential credential)
38+
{
39+
return entries;
40+
}
41+
42+
43+
public string GetCN(DirectoryEntry dirEntry)
44+
{
45+
string entryCN = null;
46+
if(dirEntry is MockDirectoryEntry)
47+
{
48+
entryCN = (dirEntry as MockDirectoryEntry).MockCN;
49+
}
50+
else
51+
{
52+
entryCN = dirEntry.Properties[MockAdHelper.CN][0].ToString();
53+
}
54+
55+
return entryCN;
56+
}
57+
58+
public void DeleteEntry(DirectoryEntry dirEntry)
59+
{
60+
// do nothing
61+
}
62+
63+
public void SetEntries(string[] ObjNames)
64+
{
65+
entries.Clear();
66+
foreach(string objName in ObjNames)
67+
{
68+
entries.Add(new MockDirectoryEntry(objName));
69+
}
70+
}
71+
}
72+
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Common/RemoteAppClient.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace Microsoft.WindowsAzure.Commands.RemoteApp.Test
2424
using System.Threading;
2525
using System.Threading.Tasks;
2626
using Microsoft.Azure;
27+
using Microsoft.WindowsAzure.Commands.RemoteApp.Test.Common;
2728

2829

2930
public class RemoteAppClientCredentials : SubscriptionCloudCredentials
@@ -96,6 +97,7 @@ protected RemoteAppClientTest()
9697
{
9798
CommandRuntime = mockCommandRuntime,
9899
Client = remoteAppManagementClientMock.Object,
100+
ActiveDirectoryHelper = new MockAdHelper(),
99101
MgmtClient = mgmtClient.Object
100102
};
101103

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Common/VmObjects.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,50 @@ public static int SetUpDefaultRemoteAppVm(Mock<IRemoteAppManagementClient> clien
7070

7171
return mockVmList.Count;
7272
}
73+
74+
public static int SetUpStaleVmObjectsTest(Mock<IRemoteAppManagementClient> clientMock, string collectionName, string[] vmNames)
75+
{
76+
CollectionVmsListResult response = new CollectionVmsListResult();
77+
ActiveDirectoryConfigResult getAdResponse = new ActiveDirectoryConfigResult()
78+
{
79+
ActiveDirectoryConfig = new ActiveDirectoryConfig()
80+
{
81+
DomainName = "contoso.com",
82+
OrganizationalUnit = null,
83+
UserName = "user",
84+
Password = "********"
85+
}
86+
};
87+
88+
response.Vms = new List<RemoteAppVm>();
89+
foreach(string vmName in vmNames)
90+
{
91+
response.Vms.Add(new RemoteAppVm()
92+
{
93+
VirtualMachineName = vmName,
94+
LoggedOnUserUpns = { }
95+
});
96+
};
97+
98+
mockVmList = new List<RemoteAppVm>();
99+
foreach (RemoteAppVm vm in response.Vms)
100+
{
101+
RemoteAppVm mockVm = new RemoteAppVm()
102+
{
103+
VirtualMachineName = vm.VirtualMachineName,
104+
LoggedOnUserUpns = vm.LoggedOnUserUpns
105+
};
106+
mockVmList.Add(mockVm);
107+
}
108+
109+
ISetup<IRemoteAppManagementClient, Task<CollectionVmsListResult>> setup = clientMock.Setup(c => c.Collections.ListVmsAsync(collectionName, It.IsAny<CancellationToken>()));
110+
setup.Returns(Task.Factory.StartNew(() => response));
111+
112+
ISetup<IRemoteAppManagementClient, Task<ActiveDirectoryConfigResult>> setupGetAd = clientMock.Setup(c => c.Collections.GetAdAsync(collectionName, It.IsAny<CancellationToken>()));
113+
setupGetAd.Returns(Task.Factory.StartNew(() => getAdResponse));
114+
115+
return mockVmList.Count;
116+
}
117+
73118
}
74119
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp.Test/Vm/RemoteAppVm.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,58 @@ public void GetVm()
111111
Assert.Equal<string>(vmName, resultVms[0].VirtualMachineName);
112112
Assert.Equal<string>(loggedInUserUpn, resultVms[0].LoggedOnUserUpns[0]);
113113
}
114+
115+
[Fact]
116+
[Trait(Category.AcceptanceType, Category.CheckIn)]
117+
public void GetStaleAdVmObjects()
118+
{
119+
int countOfExpectedVms = 0;
120+
GetAzureRemoteAppVmStaleAdObjects mockCmdlet = SetUpTestCommon<GetAzureRemoteAppVmStaleAdObjects>();
121+
IEnumerable<string> result = null;
122+
IList<string> resulAdObjs = null;
123+
124+
string[] existingVms = new string[] {"abcdefgh0003", "abcdefgh0004", "abcdefgh0005"};
125+
string[] adObjects = new string[] { "abcdefgh0000", "abcdefgh0002", "abcdefgh0003", "abcdefgh0004", "abcdefgh0005", "abcdefgh0006" };
126+
string[] expectedResult = new string[] { "abcdefgh0000", "abcdefgh0002" };
127+
128+
// Required parameters for this test
129+
mockCmdlet.CollectionName = collectionName;
130+
131+
// Setup the environment for testing this cmdlet
132+
countOfExpectedVms = MockObject.SetUpStaleVmObjectsTest(
133+
remoteAppManagementClientMock,
134+
collectionName,
135+
existingVms
136+
);
137+
138+
if(mockCmdlet.ActiveDirectoryHelper is MockAdHelper)
139+
{
140+
(mockCmdlet.ActiveDirectoryHelper as MockAdHelper).SetEntries(adObjects);
141+
}
142+
143+
mockCmdlet.ResetPipelines();
144+
145+
Log("Calling Get-AzureRemoteAppVmStaleAdObjects which should return list of stale Vm objects.");
146+
147+
mockCmdlet.ExecuteCmdlet();
148+
if (mockCmdlet.runTime().ErrorStream.Count != 0)
149+
{
150+
Assert.True(false,
151+
String.Format("Get-AzureRemoteAppVmStaleAdObjects returned the following error {0}.",
152+
mockCmdlet.runTime().ErrorStream[0].Exception.Message
153+
)
154+
);
155+
}
156+
157+
result = LanguagePrimitives.GetEnumerable(mockCmdlet.runTime().OutputPipeline).Cast<string>();
158+
159+
Assert.NotNull(result);
160+
Assert.Equal(expectedResult.Length, result.Count());
161+
162+
foreach (string staleObj in result)
163+
{
164+
Assert.True(expectedResult.Contains(staleObj));
165+
}
166+
}
114167
}
115168
}

src/ServiceManagement/RemoteApp/Commands.RemoteApp/Commands.RemoteApp.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,10 @@
191191
<Compile Include="Common\AdHelper.cs" />
192192
<Compile Include="Common\CmdRuntime.cs" />
193193
<Compile Include="Common\Exception.cs" />
194+
<Compile Include="Common\IAdHelper.cs" />
194195
<Compile Include="Common\LongRunningTask.cs" />
195196
<Compile Include="Common\RdsCmdlet.cs" />
197+
<Compile Include="Common\RdsStaleAdObjectCmdlet.cs" />
196198
<Compile Include="Common\RemoteAppRegEx.cs" />
197199
<Compile Include="OperationalResult\GetAzureRemoteAppOperationResult.cs" />
198200
<Compile Include="RemoteProgram\GetAzureRemoteAppProgram.cs" />
@@ -213,9 +215,9 @@
213215
<Compile Include="TemplateImage\RemoveAzureRemoteAppTemplateImage.cs" />
214216
<Compile Include="TemplateImage\RenameAzureRemoteAppTemplateImage.cs" />
215217
<Compile Include="TemplateImage\TemplateImage.cs" />
216-
<Compile Include="Vm\ClearAzureRemoteAppVmStaleAdObjects.cs" />
218+
<Compile Include="Vm\ClearAzureRemoteAppVmStaleAdObject.cs" />
217219
<Compile Include="Vm\GetAzureRemoteAppVm.cs" />
218-
<Compile Include="Vm\GetAzureRemoteAppVmStaleAdObjects.cs" />
220+
<Compile Include="Vm\GetAzureRemoteAppVmStaleAdObject.cs" />
219221
<Compile Include="Vm\RestartAzureRemoteAppVm.cs" />
220222
<Compile Include="Vnet\GetAzureRemoteAppVnet.cs" />
221223
<Compile Include="Vnet\GetAzureRemoteAppVpnDeviceConfigScript.cs" />

src/ServiceManagement/RemoteApp/Commands.RemoteApp/Common/AdHelper.cs

Lines changed: 34 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,36 +25,21 @@
2525

2626
namespace Microsoft.WindowsAzure.Management.RemoteApp.Cmdlets
2727
{
28-
class AdHelper
28+
class AdHelper : IAdHelper
2929
{
3030
internal const int VMNameLength = 12;
31-
public static string ConvertToUnsecureString(SecureString securePassword)
32-
{
33-
string password = null;
34-
35-
if (securePassword != null)
36-
{
37-
IntPtr unmanagedString = IntPtr.Zero;
38-
try
39-
{
40-
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
41-
password = Marshal.PtrToStringUni(unmanagedString);
42-
}
43-
finally
44-
{
45-
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
46-
}
47-
}
48-
49-
return password;
50-
}
31+
internal const string CN = "cn";
5132

52-
public static IList<DirectoryEntry> GetVmAdEntries(string domainName, string OU, string vmNamePrefix, string maxName, PSCredential credential)
33+
public IList<DirectoryEntry> GetVmAdEntries(string domainName, string OU, string vmNamePrefix, PSCredential credential)
5334
{
5435
// may throw InvalidOperationException and NotSupportedException
5536

5637
List<DirectoryEntry> results = null;
57-
38+
string userName = null;
39+
string password = null;
40+
DirectoryEntry directoryEntry = null;
41+
DirectorySearcher directorySearcher = null;
42+
SearchResultCollection searchResults = null;
5843
DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, domainName);
5944

6045
Domain domain = Domain.GetDomain(context);
@@ -66,77 +51,62 @@ public static IList<DirectoryEntry> GetVmAdEntries(string domainName, string OU,
6651
(String.IsNullOrWhiteSpace(OU) ? "" : "/" + OU)
6752
);
6853

69-
string userName = null;
70-
string password = null;
7154

7255
if ((credential != null) && (credential.UserName != null))
7356
{
7457
userName = credential.UserName;
7558
password = ConvertToUnsecureString(credential.Password);
7659
}
7760

78-
DirectoryEntry directoryEntry = new DirectoryEntry(path, userName, password);
79-
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry)
61+
directoryEntry = new DirectoryEntry(path, userName, password);
62+
directorySearcher = new DirectorySearcher(directoryEntry)
8063
{
8164
Filter = String.Format("(&(objectClass=computer)(name={0}*))", vmNamePrefix)
8265
};
8366

84-
SearchResultCollection searchResults = directorySearcher.FindAll();
67+
searchResults = directorySearcher.FindAll();
8568

8669
results = new List<DirectoryEntry>();
8770

8871
foreach (SearchResult searchResult in searchResults)
8972
{
90-
string name = searchResult.Properties["cn"][0].ToString();
91-
92-
if ((name.Length == AdHelper.VMNameLength) && ((maxName == null) || (String.Compare(name, maxName, true) < 0)))
93-
{
94-
DirectoryEntry computerToDel = searchResult.GetDirectoryEntry();
95-
results.Add(computerToDel);
96-
}
73+
DirectoryEntry entry = searchResult.GetDirectoryEntry();
74+
results.Add(entry);
9775
}
9876

9977
return results;
10078
}
10179

102-
public static IList<DirectoryEntry> GetVmAdStaleEntries(IList<RemoteAppVm> vmList, ActiveDirectoryConfig adConfig, PSCredential credential)
80+
protected string ConvertToUnsecureString(SecureString securePassword)
10381
{
104-
Dictionary<string, string> vmPrefixes = new Dictionary<string, string>();
105-
foreach (RemoteAppVm vm in vmList)
82+
string password = null;
83+
84+
if (securePassword != null)
10685
{
107-
string vmNamePrefix = vm.VirtualMachineName.Substring(0, 8);
108-
if (vmPrefixes.ContainsKey(vmNamePrefix))
109-
{
110-
if (String.Compare(vm.VirtualMachineName, vmPrefixes[vmNamePrefix], true) < 0)
111-
{
112-
vmPrefixes[vmNamePrefix] = vm.VirtualMachineName;
113-
}
114-
}
115-
else
86+
IntPtr unmanagedString = IntPtr.Zero;
87+
try
11688
{
117-
vmPrefixes.Add(vmNamePrefix, vm.VirtualMachineName);
89+
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
90+
password = Marshal.PtrToStringUni(unmanagedString);
11891
}
119-
}
120-
121-
List<DirectoryEntry> staleVmEntries = new List<DirectoryEntry>();
122-
123-
foreach (string vmNamePrefix in vmPrefixes.Keys)
124-
{
125-
IList<DirectoryEntry> adEntries = AdHelper.GetVmAdEntries(
126-
adConfig.DomainName,
127-
adConfig.OrganizationalUnit,
128-
vmNamePrefix,
129-
vmPrefixes[vmNamePrefix],
130-
credential);
131-
132-
foreach (DirectoryEntry adEntry in adEntries)
92+
finally
13393
{
134-
staleVmEntries.Add(adEntry);
94+
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
13595
}
13696
}
13797

138-
return staleVmEntries;
98+
return password;
13999
}
140100

101+
public string GetCN(DirectoryEntry dirEntry)
102+
{
103+
return dirEntry.Properties[AdHelper.CN][0].ToString();
104+
}
105+
106+
public void DeleteEntry(DirectoryEntry dirEntry)
107+
{
108+
dirEntry.DeleteTree();
109+
dirEntry.CommitChanges();
110+
}
141111
}
142112
}

0 commit comments

Comments
 (0)