-
Notifications
You must be signed in to change notification settings - Fork 192
Multi Profile Support - Part 1 #254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
457aa63
Add script to generate profiles per module.
peombwa 108158c
Generate national cloud aware profile definitions.
peombwa 3ef5c13
Consume profile definitions when generating modules.
peombwa cc723f0
Add Get-MgProfile and Select-MgProfile cmdlets.
peombwa 4b671ac
Add supported profiles to module manifest.
peombwa 0572d34
Merge branch 'milestone/0.7.0' into po/multiprofile
peombwa d4b511f
Export SelectMgProfile & GetMgProfile cmdlet.
peombwa 6a17330
Remove TODOs
peombwa bb1af5d
Address feedback.
peombwa 6b76287
Merge branch 'milestone/0.9.0' into po/multiprofile
peombwa c679cd0
Merge branch 'dev' into po/multiprofile
peombwa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets | ||
{ | ||
using Microsoft.Graph.PowerShell.Authentication.Extensions; | ||
using Microsoft.Graph.PowerShell.Authentication.Models; | ||
using System; | ||
using System.Linq; | ||
using System.Management.Automation; | ||
using static Microsoft.Graph.PowerShell.Authentication.Common.GraphProfile; | ||
|
||
[Cmdlet(VerbsCommon.Get, "MgProfile")] | ||
[OutputType(typeof(PSGraphServiceProfile))] | ||
public class GetMgProfile: PSCmdlet | ||
{ | ||
[Parameter(Mandatory = false)] | ||
[ValidateNotNullOrEmpty] | ||
public string[] ModuleName { get; set; } | ||
|
||
[Parameter(Mandatory = false)] | ||
public SwitchParameter ListAvailable { get; set; } | ||
|
||
protected override void ProcessRecord() | ||
{ | ||
base.ProcessRecord(); | ||
try | ||
{ | ||
bool isModuleNameBound = this.IsBound(nameof(ModuleName)); | ||
bool isListAvailableBound = this.IsBound(nameof(ListAvailable)); | ||
string[] moduleNames = isModuleNameBound ? ModuleName : new string[] { }; | ||
string[] profiles = isModuleNameBound || isListAvailableBound | ||
? GetProfiles(InvokeCommand, isListAvailableBound, moduleNames) | ||
: new string[] { GraphSession.Instance.SelectedProfile }; | ||
if (profiles.Any((p) => !string.IsNullOrWhiteSpace(p))) | ||
{ | ||
WriteObject(profiles.Where((profile) => !string.IsNullOrWhiteSpace(profile)) | ||
.Select((p) => PSGraphServiceProfile.Create(p)), true); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
WriteError(new ErrorRecord(ex, string.Empty, ErrorCategory.CloseError, null)); | ||
} | ||
} | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
src/Authentication/Authentication/Cmdlets/SelectMgProfile.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets | ||
{ | ||
using Microsoft.Graph.PowerShell.Authentication.Extensions; | ||
using System; | ||
using System.Linq; | ||
using System.Management.Automation; | ||
using static Microsoft.Graph.PowerShell.Authentication.Common.GraphProfile; | ||
|
||
/// <summary> | ||
/// Select the current Microsoft Graph profile. | ||
/// </summary> | ||
[Cmdlet(VerbsCommon.Select, "MgProfile", SupportsShouldProcess = true)] | ||
[OutputType(typeof(bool))] | ||
public class SelectMgProfile: PSCmdlet | ||
{ | ||
[Parameter(Mandatory = true)] | ||
[Alias("ProfileName")] | ||
[ValidateNotNullOrEmpty] | ||
public string Name { get; set; } | ||
|
||
[Parameter] | ||
public SwitchParameter PassThru { get; set; } | ||
|
||
protected override void ProcessRecord() | ||
{ | ||
base.ProcessRecord(); | ||
try | ||
{ | ||
if (this.IsParameterBound(c => c.Name)) | ||
{ | ||
PSModuleInfo[] modules = GetModules(InvokeCommand).Where(m => GetProfiles(m).Contains(Name)).ToArray(); | ||
string moduleList = string.Join(", ", modules.Select(m => m.Name)); | ||
if (ShouldProcess($"Modules {moduleList}", $"Load modules with profile {Name}")) | ||
{ | ||
GraphSession.Instance.SelectedProfile = Name; | ||
ReloadModules(InvokeCommand, modules); | ||
if (PassThru.IsPresent && PassThru.ToBool()) | ||
{ | ||
WriteObject(true); | ||
} | ||
} | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
WriteError(new ErrorRecord(ex, string.Empty, ErrorCategory.CloseError, null)); | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Common | ||
{ | ||
using System; | ||
using System.Management.Automation; | ||
using System.Linq; | ||
using System.Collections; | ||
using System.Collections.ObjectModel; | ||
using System.IO; | ||
|
||
/// <summary> | ||
/// Methods for working with Microsoft Graph profiles. | ||
/// </summary> | ||
internal static class GraphProfile | ||
{ | ||
public static string[] GetProfiles(CommandInvocationIntrinsics invokeCommand, bool listAvailable = false, params string[] moduleNames) | ||
{ | ||
return GetModules(invokeCommand, listAvailable, moduleNames).SelectMany(GetProfiles).Distinct().ToArray(); | ||
} | ||
|
||
public static PSModuleInfo[] GetModules(CommandInvocationIntrinsics invokeCommand, bool listAvailable = false, params string[] moduleNames) | ||
{ | ||
string nameParameter = $" -Name { (moduleNames != null && moduleNames.Any() ? GetCommaSeparatedQuotedList(moduleNames) : "Microsoft.Graph*" )}"; | ||
peombwa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
string listAvailableParameter = listAvailable ? " -ListAvailable" : String.Empty; | ||
string command = $"Get-Module{nameParameter}{listAvailableParameter}"; | ||
Collection<PSObject> modules = listAvailable ? PowerShell.Create().AddScript(command).Invoke<PSObject>() : invokeCommand.NewScriptBlock(command).Invoke(); | ||
return modules != null ? modules.Select(m => m?.BaseObject as PSModuleInfo).Where(m => m != null).ToArray() : new PSModuleInfo[] { }; | ||
} | ||
|
||
public static string[] GetProfiles(PSModuleInfo moduleInfo) | ||
peombwa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
var moduleProfileInfo = (moduleInfo?.PrivateData as Hashtable)?["Profiles"]; | ||
var moduleProfiles = moduleProfileInfo as object[] ?? (moduleProfileInfo != null ? new[] { moduleProfileInfo } : null); | ||
return moduleProfiles != null && moduleProfiles.Any() ? moduleProfiles.Cast<string>().ToArray() : new string[] { }; | ||
} | ||
|
||
public static void ReloadModules(CommandInvocationIntrinsics invokeCommand, params PSModuleInfo[] moduleInfos) | ||
{ | ||
var modulePaths = GetCommaSeparatedQuotedList(moduleInfos.Select(GetModulePath).ToArray()); | ||
if (!String.IsNullOrEmpty(modulePaths)) | ||
{ | ||
var command = $"Import-Module -Name {modulePaths} -Force"; | ||
invokeCommand.NewScriptBlock(command).Invoke(); | ||
} | ||
} | ||
|
||
private static string GetCommaSeparatedQuotedList(params string[] items) | ||
{ | ||
return string.Join(", ", items.Where(i => !string.IsNullOrEmpty(i)).Select(i => $"'{i}'")); | ||
} | ||
|
||
private static string GetModulePath(PSModuleInfo moduleInfo) | ||
{ | ||
var scriptPsd1 = Path.Combine(moduleInfo.ModuleBase, $"{moduleInfo.Name}.psd1"); | ||
return moduleInfo.ModuleType == ModuleType.Script && File.Exists(scriptPsd1) ? scriptPsd1 : moduleInfo.Path; | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
src/Authentication/Authentication/Extensions/IEnumerableExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Extensions | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
internal static class IEnumerableExtensions | ||
{ | ||
/// <summary> | ||
/// Perform an action on each element of a sequence. | ||
/// </summary> | ||
/// <typeparam name="T">Type of elements in the sequence.</typeparam> | ||
/// <param name="sequence">The sequence.</param> | ||
/// <param name="action">The action to perform.</param> | ||
public static void ForEach<T>(this IEnumerable<T> sequence, Action<T> action) | ||
{ | ||
foreach (T element in sequence) | ||
{ | ||
action(element); | ||
} | ||
} | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/Authentication/Authentication/Extensions/PSCmdletExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Extensions | ||
{ | ||
using Microsoft.Graph.PowerShell.Authentication.Helpers; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.ObjectModel; | ||
using System.Linq.Expressions; | ||
using System.Management.Automation; | ||
internal static class PSCmdletExtensions | ||
{ | ||
/// <summary> | ||
/// Executes a PowerShell script. | ||
/// </summary> | ||
/// <typeparam name="T">The output type to return.</typeparam> | ||
/// <param name="cmdlet">The executing cmdlet.</param> | ||
/// <param name="contents">The PowerShell scrip to execute.</param> | ||
peombwa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// <returns>The result for the executed script.</returns> | ||
public static List<T> ExecuteScript<T>(this PSCmdlet cmdlet, string contents) | ||
{ | ||
List<T> output = new List<T>(); | ||
|
||
using (PowerShell powershell = PowerShell.Create(RunspaceMode.CurrentRunspace)) | ||
{ | ||
powershell.AddScript(contents); | ||
Collection<T> result = powershell.Invoke<T>(); | ||
|
||
if (cmdlet.SessionState != null) | ||
{ | ||
powershell.Streams.Error.ForEach(e => cmdlet.WriteError(e)); | ||
powershell.Streams.Verbose.ForEach(r => cmdlet.WriteVerbose(r.Message)); | ||
powershell.Streams.Warning.ForEach(r => cmdlet.WriteWarning(r.Message)); | ||
} | ||
|
||
if (result != null && result.Count > 0) | ||
{ | ||
output.AddRange(result); | ||
} | ||
} | ||
|
||
return output; | ||
} | ||
|
||
/// <summary> | ||
/// Determines is a parameter has been provided by the user. | ||
/// </summary> | ||
/// <param name="cmdlet">The executing cmdlet.</param> | ||
/// <param name="parameterName">The name of the parameter to check.</param> | ||
/// <returns>True is the parameter was set by the user, otherwise false.</returns> | ||
public static bool IsBound(this PSCmdlet cmdlet, string parameterName) | ||
peombwa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return cmdlet.MyInvocation?.BoundParameters.ContainsKey(parameterName) ?? false; | ||
} | ||
|
||
/// <summary> | ||
/// Determines is a parameter has been provided by the user. | ||
/// </summary> | ||
/// <typeparam name="TPSCmdlet">Cmdlet type.</typeparam> | ||
/// <typeparam name="TProp">Property type.</typeparam> | ||
/// <param name="cmdlet">The executing cmdlet.</param> | ||
/// <param name="propertySelector">The parameter to check</param> | ||
/// <returns>True is the parameter was set by the user, otherwise false.</returns> | ||
public static bool IsParameterBound<TPSCmdlet, TProp>(this TPSCmdlet cmdlet, Expression<Func<TPSCmdlet, TProp>> propertySelector) where TPSCmdlet : PSCmdlet | ||
{ | ||
var propName = ((MemberExpression)propertySelector.Body).Member.Name; | ||
return cmdlet.IsBound(propName); | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/Authentication/Authentication/Extensions/StringExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// ------------------------------------------------------------------------------ | ||
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. | ||
// ------------------------------------------------------------------------------ | ||
|
||
namespace Microsoft.Graph.PowerShell.Authentication.Extensions | ||
{ | ||
using System; | ||
public static class StringExtensions | ||
{ | ||
/// <summary> | ||
/// Indicates whether a specified string is null, empty, consists only of white-space, or has the specified search value. | ||
/// </summary> | ||
/// <param name="target">The target string to look in.</param> | ||
/// <param name="searchValue">The substring to seek.</param> | ||
/// <param name="comparison">The <see cref="StringComparison"/> to use. This defaults to <see cref="StringComparison.OrdinalIgnoreCase"/>.</param> | ||
/// <returns>true if the searchValue parameter occurs within this string; otherwise false.</returns> | ||
public static bool ContainsNotNull(this string target, string searchValue, StringComparison comparison = StringComparison.OrdinalIgnoreCase) | ||
peombwa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if (string.IsNullOrWhiteSpace(target) || string.IsNullOrWhiteSpace(searchValue)) | ||
{ | ||
return false; | ||
} | ||
|
||
switch (comparison) | ||
{ | ||
case StringComparison.CurrentCultureIgnoreCase: | ||
case StringComparison.OrdinalIgnoreCase: | ||
target = target.ToLower(); | ||
searchValue = searchValue.ToLower(); | ||
break; | ||
case StringComparison.InvariantCultureIgnoreCase: | ||
target = target.ToLowerInvariant(); | ||
searchValue = searchValue.ToLowerInvariant(); | ||
break; | ||
} | ||
|
||
return target.Contains(searchValue); | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.