Skip to content

Commit 3561532

Browse files
author
Jianghao Lu
committed
Merge pull request #856 from huangpf/r098
AzureRT S53 PR - Data Collection Opt-In/Out
2 parents 50312c1 + 48edc24 commit 3561532

File tree

13 files changed

+2862
-4
lines changed

13 files changed

+2862
-4
lines changed

src/AzurePowershell.sln

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
22
# Visual Studio 2013
3-
VisualStudioVersion = 12.0.30723.0
3+
VisualStudioVersion = 12.0.40629.0
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8531411A-0137-4E27-9C5E-49E07C245048}"
66
ProjectSection(SolutionItems) = preProject
@@ -632,4 +632,7 @@ Global
632632
{678AE95D-2364-47D7-888C-3FFA6D412CC8} = {95C16AED-FD57-42A0-86C3-2CF4300A4817}
633633
{6C7D3D81-37AB-445E-8081-78A1FEC0A773} = {95C16AED-FD57-42A0-86C3-2CF4300A4817}
634634
EndGlobalSection
635+
GlobalSection(ExtensibilityGlobals) = postSolution
636+
EnterpriseLibraryConfigurationToolBinariesPathV6 = packages\EnterpriseLibrary.TransientFaultHandling.6.0.1304.0\lib\portable-net45+win+wp8;packages\EnterpriseLibrary.TransientFaultHandling.Data.6.0.1304.1\lib\NET45
637+
EndGlobalSection
635638
EndGlobal

src/Common/Commands.Common/AzurePSCmdlet.cs

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15-
using System.Collections.Concurrent;
1615
using Microsoft.Azure.Common.Authentication;
1716
using Microsoft.Azure.Common.Authentication.Models;
1817
using Microsoft.IdentityModel.Clients.ActiveDirectory;
1918
using Microsoft.WindowsAzure.Commands.Common;
2019
using Microsoft.WindowsAzure.Commands.Common.Properties;
20+
using Newtonsoft.Json;
2121
using System;
22+
using System.Collections.Concurrent;
2223
using System.Diagnostics;
2324
using System.IO;
2425
using System.Management.Automation;
26+
using System.Management.Automation.Host;
27+
using System.Threading;
2528

2629
namespace Microsoft.WindowsAzure.Commands.Utilities.Common
2730
{
@@ -31,6 +34,7 @@ public abstract class AzurePSCmdlet : PSCmdlet
3134
private RecordingTracingInterceptor _httpTracingInterceptor;
3235
private DebugStreamTraceListener _adalListener;
3336
protected static AzureProfile _currentProfile = null;
37+
protected static AzurePSDataCollectionProfile _dataCollectionProfile = null;
3438

3539
[Parameter(Mandatory = false, HelpMessage = "In-memory profile.")]
3640
public AzureProfile Profile { get; set; }
@@ -147,12 +151,161 @@ protected static void SetTokenCacheForProfile(AzureProfile profile)
147151
}
148152
}
149153

154+
/// <summary>
155+
/// Initialize the data collection profile
156+
/// </summary>
157+
protected static void InitializeDataCollectionProfile()
158+
{
159+
if (_dataCollectionProfile != null && _dataCollectionProfile.EnableAzureDataCollection.HasValue)
160+
{
161+
return;
162+
}
163+
164+
// Get the value of the environment variable for Azure PS data collection setting.
165+
string value = Environment.GetEnvironmentVariable(AzurePSDataCollectionProfile.EnvironmentVariableName);
166+
if (!string.IsNullOrWhiteSpace(value))
167+
{
168+
if (string.Equals(value, bool.FalseString, StringComparison.OrdinalIgnoreCase))
169+
{
170+
// Disable data collection only if it is explictly set to 'false'.
171+
_dataCollectionProfile = new AzurePSDataCollectionProfile(true);
172+
}
173+
else if (string.Equals(value, bool.TrueString, StringComparison.OrdinalIgnoreCase))
174+
{
175+
// Enable data collection only if it is explictly set to 'true'.
176+
_dataCollectionProfile = new AzurePSDataCollectionProfile(false);
177+
}
178+
}
179+
180+
// If the environment value is null or empty, or not correctly set, try to read the setting from default file location.
181+
if (_dataCollectionProfile == null)
182+
{
183+
string fileFullPath = Path.Combine(AzureSession.ProfileDirectory, AzurePSDataCollectionProfile.DefaultFileName);
184+
if (File.Exists(fileFullPath))
185+
{
186+
string contents = File.ReadAllText(fileFullPath);
187+
_dataCollectionProfile = JsonConvert.DeserializeObject<AzurePSDataCollectionProfile>(contents);
188+
}
189+
}
190+
191+
// If the environment variable or file content is not set, create a new profile object.
192+
if (_dataCollectionProfile == null)
193+
{
194+
_dataCollectionProfile = new AzurePSDataCollectionProfile();
195+
}
196+
}
197+
198+
/// <summary>
199+
/// Get the data collection profile
200+
/// </summary>
201+
protected static AzurePSDataCollectionProfile GetDataCollectionProfile()
202+
{
203+
if (_dataCollectionProfile == null)
204+
{
205+
InitializeDataCollectionProfile();
206+
}
207+
208+
return _dataCollectionProfile;
209+
}
210+
211+
/// <summary>
212+
/// Save the current data collection profile Json data into the default file path
213+
/// </summary>
214+
/// <param name="profile"></param>
215+
protected void SaveDataCollectionProfile()
216+
{
217+
if (_dataCollectionProfile == null)
218+
{
219+
InitializeDataCollectionProfile();
220+
}
221+
222+
string fileFullPath = Path.Combine(AzureSession.ProfileDirectory, AzurePSDataCollectionProfile.DefaultFileName);
223+
var contents = JsonConvert.SerializeObject(_dataCollectionProfile);
224+
AzureSession.DataStore.WriteFile(fileFullPath, contents);
225+
WriteWarning(string.Format(Resources.DataCollectionSaveFileInformation, fileFullPath));
226+
}
227+
228+
protected bool CheckIfInteractive()
229+
{
230+
if (this.Host == null || this.Host.UI == null || this.Host.UI.RawUI == null)
231+
{
232+
return false;
233+
}
234+
235+
bool interactive = true;
236+
try
237+
{
238+
var test = this.Host.UI.RawUI.KeyAvailable;
239+
}
240+
catch (HostException ex)
241+
{
242+
if (ex.Message.StartsWith("A command that prompts the user failed"))
243+
{
244+
interactive = false;
245+
}
246+
else
247+
{
248+
throw ex;
249+
}
250+
}
251+
252+
return interactive;
253+
}
254+
255+
/// <summary>
256+
/// Prompt for the current data collection profile
257+
/// </summary>
258+
/// <param name="profile"></param>
259+
protected void PromptForDataCollectionProfileIfNotExists()
260+
{
261+
// Initialize it from the environment variable or profile file.
262+
InitializeDataCollectionProfile();
263+
264+
if (CheckIfInteractive() && !_dataCollectionProfile.EnableAzureDataCollection.HasValue)
265+
{
266+
WriteWarning(Resources.DataCollectionPrompt);
267+
268+
const double timeToWaitInSeconds = 60;
269+
var status = string.Format(Resources.DataCollectionConfirmTime, timeToWaitInSeconds);
270+
ProgressRecord record = new ProgressRecord(0, Resources.DataCollectionActivity, status);
271+
272+
var startTime = DateTime.Now;
273+
var endTime = DateTime.Now;
274+
double elapsedSeconds = 0;
275+
276+
while (!this.Host.UI.RawUI.KeyAvailable && elapsedSeconds < timeToWaitInSeconds)
277+
{
278+
Thread.Sleep(TimeSpan.FromMilliseconds(10));
279+
endTime = DateTime.Now;
280+
281+
elapsedSeconds = (endTime - startTime).TotalSeconds;
282+
record.PercentComplete = ((int)elapsedSeconds * 100 / (int)timeToWaitInSeconds);
283+
WriteProgress(record);
284+
}
285+
286+
bool enabled = false;
287+
if (this.Host.UI.RawUI.KeyAvailable)
288+
{
289+
KeyInfo keyInfo = this.Host.UI.RawUI.ReadKey(ReadKeyOptions.NoEcho | ReadKeyOptions.AllowCtrlC | ReadKeyOptions.IncludeKeyDown);
290+
enabled = (keyInfo.Character == 'Y' || keyInfo.Character == 'y');
291+
}
292+
293+
_dataCollectionProfile.EnableAzureDataCollection = enabled;
294+
295+
WriteWarning(enabled ? Resources.DataCollectionConfirmYes : Resources.DataCollectionConfirmNo);
296+
297+
SaveDataCollectionProfile();
298+
}
299+
}
300+
150301
/// <summary>
151302
/// Cmdlet begin process. Write to logs, setup Http Tracing and initialize profile
152303
/// </summary>
153304
protected override void BeginProcessing()
154305
{
155306
InitializeProfile();
307+
PromptForDataCollectionProfileIfNotExists();
308+
156309
if (string.IsNullOrEmpty(ParameterSetName))
157310
{
158311
WriteDebugWithTimestamp(string.Format(Resources.BeginProcessingWithoutParameterSetLog, this.GetType().Name));
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using System;
16+
using System.IO;
17+
using Newtonsoft.Json;
18+
using Microsoft.Azure.Common.Authentication;
19+
20+
namespace Microsoft.WindowsAzure.Commands.Common
21+
{
22+
public class AzurePSDataCollectionProfile
23+
{
24+
public const string EnvironmentVariableName = "Azure_PS_Data_Collection";
25+
public static string DefaultFileName = "AzureDataCollectionProfile.json";
26+
27+
public AzurePSDataCollectionProfile()
28+
{
29+
}
30+
31+
public AzurePSDataCollectionProfile(bool enable)
32+
{
33+
EnableAzureDataCollection = enable;
34+
}
35+
36+
[JsonProperty(PropertyName = "enableAzureDataCollection")]
37+
public bool? EnableAzureDataCollection { get; set; }
38+
}
39+
}

src/Common/Commands.Common/Commands.Common.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
<Reference Include="System.Xml" />
139139
</ItemGroup>
140140
<ItemGroup>
141+
<Compile Include="AzurePSDataCollectionProfile.cs" />
141142
<Compile Include="AzurePowerShell.cs" />
142143
<Compile Include="ComputeCloudException.cs" />
143144
<Compile Include="Constants.cs" />

src/Common/Commands.Common/Properties/Resources.Designer.cs

Lines changed: 58 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Common/Commands.Common/Properties/Resources.resx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,4 +1468,32 @@ The file needs to be a PowerShell script (.ps1 or .psm1).</value>
14681468
<data name="CannotChangeBuiltinEnvironment" xml:space="preserve">
14691469
<value>Cannot change built-in environment {0}.</value>
14701470
</data>
1471+
<data name="DataCollectionPrompt" xml:space="preserve">
1472+
<value>Microsoft Azure PowerShell collects data about how users use PowerShell cmdlets and some problems they encounter. Microsoft uses this information to improve our PowerShell cmdlets. Participation is voluntary and when you choose to participate your device automatically sends information to Microsoft about how you use Azure PowerShell.
1473+
1474+
If you choose to participate, you can stop at any time by using Azure PowerShell as follows:
1475+
1. Use the Disable-AzureDataCollection cmdlet to turn the feature Off. The cmdlet can be found in the AzureResourceManager module
1476+
To disable data collection: PS &gt; Disable-AzureDataCollection
1477+
1478+
If you choose to not participate, you can enable at any time by using Azure PowerShell as follows:
1479+
1. Use the Enable-AzureDataCollection cmdlet to turn the feature On. The cmdlet can be found in the AzureResourceManager module
1480+
To enable data collection: PS &gt; Enable-AzureDataCollection
1481+
1482+
Select Y to enable data collection [Y/N]:</value>
1483+
</data>
1484+
<data name="DataCollectionActivity" xml:space="preserve">
1485+
<value>Microsoft Azure PowerShell Data Collection Confirmation</value>
1486+
</data>
1487+
<data name="DataCollectionConfirmNo" xml:space="preserve">
1488+
<value>You choose not to participate in Microsoft Azure PowerShell data collection.</value>
1489+
</data>
1490+
<data name="DataCollectionConfirmTime" xml:space="preserve">
1491+
<value>This confirmation message will be dismissed in '{0}' second(s)...</value>
1492+
</data>
1493+
<data name="DataCollectionConfirmYes" xml:space="preserve">
1494+
<value>You choose to participate in Microsoft Azure PowerShell data collection.</value>
1495+
</data>
1496+
<data name="DataCollectionSaveFileInformation" xml:space="preserve">
1497+
<value>The setting profile has been saved to the following path '{0}'.</value>
1498+
</data>
14711499
</root>

src/Common/Commands.Profile/Commands.Profile.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@
140140
<Compile Include="Models\PSAzureEnvironment.cs" />
141141
<Compile Include="Models\PSAzureSubscription.cs" />
142142
<Compile Include="Models\PSAzureSubscriptionExtended.cs" />
143+
<Compile Include="DataCollection\EnableAzureDataCollection.cs" />
144+
<Compile Include="DataCollection\DisableAzureDataCollection.cs" />
143145
<Compile Include="Profile\SelectAzureProfile.cs" />
144146
<Compile Include="Profile\NewAzureProfile.cs" />
145147
<Compile Include="Profile\ClearAzureProfile.cs" />

0 commit comments

Comments
 (0)