User feature update (#225)
This commit is contained in:
Родитель
f8ec1f46fd
Коммит
7660dae8e0
|
@ -26,53 +26,39 @@ Gets the sign-in activities for the specified user.
|
|||
|
||||
### Example 1
|
||||
```powershell
|
||||
PS C:\> Get-PartnerUserSignInActivity -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e'
|
||||
```
|
||||
|
||||
Gets the sign-in activities for the specified user.
|
||||
|
||||
### Example 2
|
||||
```powershell
|
||||
PS C:\> Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e'
|
||||
```
|
||||
|
||||
Gets the sign-in activities from the past seven days for the specified user.
|
||||
|
||||
### Example 3
|
||||
### Example 2
|
||||
```powershell
|
||||
PS C:\> $users = Get-PartnerUser
|
||||
PS C:\> $activities = $users.ForEach({Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
|
||||
PS C:\> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}}
|
||||
PS C:\> Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e' | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}}
|
||||
```
|
||||
|
||||
Gets the sign-in activities from the past seven days that have successfully authenticated.
|
||||
Gets the successful sign-in activities from the past seven days for the specified user.
|
||||
|
||||
### Example 3
|
||||
```powershell
|
||||
PS C:\> Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e' | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null}
|
||||
```
|
||||
|
||||
Gets the successful sign-in activities from the past seven days for the specified user that were not challenged by multi-factor authentication.
|
||||
|
||||
### Example 4
|
||||
```powershell
|
||||
PS C:> $users = Get-PartnerUser
|
||||
PS C:> $activities = $users.ForEach({Get-PartnerUserSignInActivity -EndDate (Get-Date) -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
|
||||
PS C:> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.ResourceId -eq 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd'}
|
||||
PS C:\> $signIns = Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null}
|
||||
```
|
||||
|
||||
Gets the sign-in activities from the past seven days where the resource being accessed was the Partner Center API.
|
||||
Gets the successful sign-in activities all users from the past seven days in your partner tenant that were not challenged by multi-factor authentication.
|
||||
|
||||
### Example 5
|
||||
```powershell
|
||||
PS C:\> $users = Get-PartnerUser
|
||||
PS C:\> $activities = $users.ForEach({Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
|
||||
PS C:\> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null}
|
||||
PS C:\> $signIns = Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7)
|
||||
PS C:\> $signIns | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null} | ? {$_.ResourceId -eq 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd'}
|
||||
```
|
||||
|
||||
Gets the sign-in activities from the past seven days that have successfully authenticated, but have not utilized multi-factor authentication.
|
||||
|
||||
### Example 6
|
||||
```powershell
|
||||
PS C:> $users = Get-PartnerUser
|
||||
PS C:> $activities = $users.ForEach({Get-PartnerUserSignInActivity -EndDate (Get-Date) -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
|
||||
PS C:> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null} | ? {$_.ResourceId -eq 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd'}
|
||||
```
|
||||
|
||||
Gets the sign-in activities from the past seven days where the resource being accessed was the Partner Center API and the sign-in activity was not challenged for multi-factor authentication.
|
||||
Gets the successful sign-in activities from the past seven days, where the resource being assessed was the Partner Center API and were not challenged by multi-factor authentication.
|
||||
|
||||
## PARAMETERS
|
||||
|
||||
|
|
|
@ -4,13 +4,16 @@
|
|||
namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Graph;
|
||||
using Models.Authentication;
|
||||
using System.Collections.Generic;
|
||||
using Network;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[Cmdlet(VerbsCommon.Get, "PartnerUserSignInActivity"), OutputType(typeof(SignIn))]
|
||||
public class GetPartnerUserSignInActivity : PartnerAsyncCmdlet
|
||||
|
@ -20,6 +23,26 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
|
|||
/// </summary>
|
||||
private const string RequestFromNonPremiumTenant = "Authentication_RequestFromNonPremiumTenantOrB2CTenant";
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default amount of time used when calculating a random delta in the delay between retries.
|
||||
/// </summary>
|
||||
private static readonly TimeSpan DefaultClientBackoff = TimeSpan.FromSeconds(10.0);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default maximum amount of time used when calculating the exponential delay between retries.
|
||||
/// </summary>
|
||||
private static readonly TimeSpan DefaultMaxBackoff = TimeSpan.FromSeconds(30.0);
|
||||
|
||||
/// <summary>
|
||||
/// Represents the default minimum amount of time used when calculating the exponential delay between retries.
|
||||
/// </summary>
|
||||
private static readonly TimeSpan DefaultMinBackoff = TimeSpan.FromSeconds(1.0);
|
||||
|
||||
/// <summary>
|
||||
/// The queue of paged Microsoft Graph request operations.
|
||||
/// </summary>
|
||||
private static readonly Queue<IBaseRequest> PagedRequests = new Queue<IBaseRequest>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the end date portion of the query.
|
||||
/// </summary>
|
||||
|
@ -72,25 +95,89 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
|
|||
if (!string.IsNullOrEmpty(filter))
|
||||
{
|
||||
queryOptions = new List<QueryOption>
|
||||
{
|
||||
new QueryOption("$filter", $"({filter})")
|
||||
};
|
||||
{
|
||||
new QueryOption("$filter", $"({filter})")
|
||||
};
|
||||
}
|
||||
|
||||
collection = await client.AuditLogs.SignIns.Request(queryOptions).Top(500).GetAsync(CancellationToken).ConfigureAwait(false);
|
||||
signIns = new List<SignIn>(collection.CurrentPage);
|
||||
|
||||
while (collection.NextPageRequest != null)
|
||||
try
|
||||
{
|
||||
collection = await collection.NextPageRequest.GetAsync(CancellationToken).ConfigureAwait(false);
|
||||
signIns.AddRange(collection.CurrentPage);
|
||||
}
|
||||
collection = await client.AuditLogs.SignIns.Request(queryOptions).Top(500).GetAsync(CancellationToken).ConfigureAwait(false);
|
||||
signIns = new List<SignIn>(collection.CurrentPage);
|
||||
|
||||
while (collection.NextPageRequest != null)
|
||||
{
|
||||
collection = await collection.NextPageRequest.GetAsync(CancellationToken).ConfigureAwait(false);
|
||||
signIns.AddRange(collection.CurrentPage);
|
||||
}
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
{
|
||||
if (!ex.Error.Code.Equals(RequestFromNonPremiumTenant))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
signIns = await GetSignInActivitiesAsync(client).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
WriteObject(signIns, true);
|
||||
}, true);
|
||||
}
|
||||
|
||||
private async Task<List<SignIn>> GetSignInActivitiesAsync(IGraphServiceClient client)
|
||||
{
|
||||
BatchRequestContent batchRequestContent;
|
||||
BatchResponseContent batchResponseContent;
|
||||
IGraphServiceUsersCollectionPage userCollection;
|
||||
List<SignIn> signIns;
|
||||
List<User> users;
|
||||
string filter = string.Empty;
|
||||
|
||||
userCollection = await client.Users.Request().Top(500).GetAsync().ConfigureAwait(false);
|
||||
users = new List<User>(userCollection.CurrentPage);
|
||||
|
||||
while (userCollection.NextPageRequest != null)
|
||||
{
|
||||
userCollection = await userCollection.NextPageRequest.GetAsync().ConfigureAwait(false);
|
||||
users.AddRange(userCollection.CurrentPage);
|
||||
}
|
||||
|
||||
if (StartDate != null)
|
||||
{
|
||||
filter = AppendValue(filter, $"createdDateTime ge {StartDate.Value.ToString("yyyy-MM-ddTHH:mm:ssZ")}");
|
||||
}
|
||||
|
||||
if (EndDate != null)
|
||||
{
|
||||
filter = AppendValue(filter, $"createdDateTime le {EndDate.Value.ToString("yyyy-MM-ddTHH:mm:ssZ")}");
|
||||
}
|
||||
|
||||
signIns = new List<SignIn>();
|
||||
|
||||
foreach (IEnumerable<User> batch in Batch(users, 5))
|
||||
{
|
||||
batchRequestContent = new BatchRequestContent();
|
||||
|
||||
foreach (User user in batch)
|
||||
{
|
||||
batchRequestContent.AddBatchRequestStep(client.AuditLogs.SignIns.Request(new List<QueryOption>
|
||||
{
|
||||
new QueryOption("$filter", $"({AppendValue(filter, $"userId eq '{user.Id}'")})")
|
||||
}).Top(200));
|
||||
}
|
||||
|
||||
batchResponseContent = await client.Batch.Request().PostAsync(batchRequestContent, CancellationToken).ConfigureAwait(false);
|
||||
await ParseBatchResponseAsync(client, batchRequestContent, batchResponseContent, signIns).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
while (PagedRequests.Count != 0)
|
||||
{
|
||||
await ProcessPagedRequestsAsync(client, signIns).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return signIns;
|
||||
}
|
||||
|
||||
private static string AppendValue(string baseValue, string appendValue)
|
||||
{
|
||||
|
@ -101,5 +188,114 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
|
|||
|
||||
return $"{baseValue} and {appendValue}";
|
||||
}
|
||||
|
||||
private static IEnumerable<IEnumerable<T>> Batch<T>(IEnumerable<T> entities, int batchSize)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
while (size < entities.Count())
|
||||
{
|
||||
yield return entities.Skip(size).Take(batchSize);
|
||||
size += batchSize;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ParseBatchResponseAsync(IGraphServiceClient client, BatchRequestContent batchRequestContent, BatchResponseContent batchResponseContent, List<SignIn> signIns, int retryCount = 0)
|
||||
{
|
||||
AuditLogRootRestrictedSignInsCollectionResponse collection;
|
||||
Dictionary<string, HttpResponseMessage> responses;
|
||||
|
||||
client.AssertNotNull(nameof(client));
|
||||
batchRequestContent.AssertNotNull(nameof(batchRequestContent));
|
||||
batchResponseContent.AssertNotNull(nameof(batchResponseContent));
|
||||
signIns.AssertNotNull(nameof(signIns));
|
||||
|
||||
responses = await batchResponseContent.GetResponsesAsync().ConfigureAwait(false);
|
||||
|
||||
foreach (KeyValuePair<string, HttpResponseMessage> item in responses.Where(item => item.Value.IsSuccessStatusCode))
|
||||
{
|
||||
collection = await batchResponseContent
|
||||
.GetResponseByIdAsync<AuditLogRootRestrictedSignInsCollectionResponse>(item.Key).ConfigureAwait(false);
|
||||
|
||||
collection.AdditionalData.TryGetValue("@odata.nextLink", out object nextPageLink);
|
||||
string nextPageLinkString = nextPageLink as string;
|
||||
|
||||
if (!string.IsNullOrEmpty(nextPageLinkString))
|
||||
{
|
||||
collection.Value.InitializeNextPageRequest(client, nextPageLinkString);
|
||||
}
|
||||
|
||||
if (collection.Value.NextPageRequest != null)
|
||||
{
|
||||
PagedRequests.Enqueue(collection.Value.NextPageRequest);
|
||||
}
|
||||
|
||||
signIns.AddRange(collection.Value);
|
||||
}
|
||||
|
||||
if (PagedRequests.Count >= 5)
|
||||
{
|
||||
await ProcessPagedRequestsAsync(client, signIns).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await RetryRequestWithTransientFaultAsync(client, batchRequestContent, responses, signIns, ++retryCount).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ProcessPagedRequestsAsync(IGraphServiceClient client, List<SignIn> signIns)
|
||||
{
|
||||
BatchRequestContent batchRequestContent;
|
||||
BatchResponseContent batchResponseContent;
|
||||
int numberOfRequests;
|
||||
|
||||
client.AssertNotNull(nameof(client));
|
||||
signIns.AssertNotNull(nameof(signIns));
|
||||
|
||||
if (PagedRequests.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
batchRequestContent = new BatchRequestContent();
|
||||
|
||||
numberOfRequests = PagedRequests.Count > 5 ? 5 : PagedRequests.Count;
|
||||
|
||||
for (int i = 0; i < numberOfRequests; i++)
|
||||
{
|
||||
batchRequestContent.AddBatchRequestStep(PagedRequests.Dequeue());
|
||||
}
|
||||
|
||||
batchResponseContent = await client.Batch.Request().PostAsync(batchRequestContent, CancellationToken).ConfigureAwait(false);
|
||||
await ParseBatchResponseAsync(client, batchRequestContent, batchResponseContent, signIns).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task RetryRequestWithTransientFaultAsync(IGraphServiceClient client, BatchRequestContent batchRequestContent, Dictionary<string, HttpResponseMessage> responses, List<SignIn> signIns, int retryCount)
|
||||
{
|
||||
BatchRequestContent retryBatchRequestContent = new BatchRequestContent();
|
||||
BatchResponseContent batchResponseContent;
|
||||
Random random;
|
||||
double delta;
|
||||
|
||||
client.AssertNotNull(nameof(client));
|
||||
batchRequestContent.AssertNotNull(nameof(batchRequestContent));
|
||||
responses.AssertNotNull(nameof(responses));
|
||||
|
||||
if (retryCount <= 3 && responses.Where(item => item.Value.StatusCode == (HttpStatusCode)429).Any())
|
||||
{
|
||||
foreach (KeyValuePair<string, HttpResponseMessage> item in responses.Where(item => item.Value.StatusCode == (HttpStatusCode)429))
|
||||
{
|
||||
retryBatchRequestContent.AddBatchRequestStep(batchRequestContent.BatchRequestSteps[item.Key]);
|
||||
}
|
||||
|
||||
random = new Random();
|
||||
delta = (Math.Pow(2.0, retryCount) - 1.0) *
|
||||
random.Next((int)(DefaultClientBackoff.TotalMilliseconds * 0.8), (int)(DefaultClientBackoff.TotalMilliseconds * 1.2));
|
||||
|
||||
await Task.Delay((int)Math.Min(DefaultMinBackoff.TotalMilliseconds + delta, DefaultMaxBackoff.TotalMilliseconds), CancellationToken).ConfigureAwait(false);
|
||||
|
||||
batchResponseContent = await client.Batch.Request().PostAsync(retryBatchRequestContent, CancellationToken).ConfigureAwait(false);
|
||||
|
||||
await ParseBatchResponseAsync(client, retryBatchRequestContent, batchResponseContent, signIns, retryCount).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче