From 0b8309a5be0ac09963f05a3fbb8b11738d037d97 Mon Sep 17 00:00:00 2001 From: Siddharth Vaghasia Date: Sun, 9 Apr 2023 13:36:20 +0530 Subject: [PATCH 1/3] added new command Export-PnPPowerApp --- documentation/Export-PnPPowerApp.md | 198 ++++++++++++++++++ .../PowerApp/Enums/PowerAppExportStatus.cs | 23 ++ .../PowerApp/PowerAppExportPackageError.cs | 22 ++ .../PowerApp/PowerAppExportPackageResource.cs | 65 ++++++ .../PowerApp/PowerAppPackageWrapper.cs | 46 ++++ .../PowerPlatform/PowerApps/ExportPowerApp.cs | 181 ++++++++++++++++ src/Commands/Utilities/REST/RestHelper.cs | 38 ++++ 7 files changed, 573 insertions(+) create mode 100644 documentation/Export-PnPPowerApp.md create mode 100644 src/Commands/Model/PowerPlatform/PowerApp/Enums/PowerAppExportStatus.cs create mode 100644 src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageError.cs create mode 100644 src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageResource.cs create mode 100644 src/Commands/Model/PowerPlatform/PowerApp/PowerAppPackageWrapper.cs create mode 100644 src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs diff --git a/documentation/Export-PnPPowerApp.md b/documentation/Export-PnPPowerApp.md new file mode 100644 index 000000000..3a6d66996 --- /dev/null +++ b/documentation/Export-PnPPowerApp.md @@ -0,0 +1,198 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Export-PnPPowerApp.html +external help file: PnP.PowerShell.dll-Help.xml +title: Export-PnPPowerApp +--- + +# Export-PnPPowerApp + +## SYNOPSIS + +**Required Permissions** + +* Azure: management.azure.com + +Exports a Microsoft Power App + +## SYNTAX + +``` +Export-PnPPowerApp -Environment -Identity + [-PackageDisplayName ] [-PackageDescription ] [-PackageCreatedBy ] + [-PackageSourceEnvironment ] [-OutPath ] [-Force] [-Connection ] + [] +``` + +## DESCRIPTION +This cmdlet exports a Microsoft Power App as zip package. + +Many times exporting a Microsoft Power App will not be possible due to various reasons such as connections having gone stale, SharePoint sites referenced no longer existing or other configuration errors in the App. To display these errors when trying to export a App, provide the -Verbose flag with your export request. If not provided, these errors will silently be ignored. + +## EXAMPLES + +### Example 1 +```powershell +$environment = Get-PnPPowerPlatformEnvironment -IsDefault $true +Export-PnPPowerApp -Environment $environment -Identity fba63225-baf9-4d76-86a1-1b42c917a182 -OutPath "C:\Users\user1\Downloads\test_20230408152624.zip" +``` + +This will export the specified Microsoft Power App from the default Power Platform environment as an output to the path specified in the command as -OutPath + +### Example 2 +```powershell +$environment = Get-PnPPowerPlatformEnvironment -IsDefault $true +Export-PnPPowerApp -Environment $environment -Identity fba63225-baf9-4d76-86a1-1b42c917a182 -OutPath "C:\Users\user1\Downloads\test_20230408152624.zip" -PackageDisplayName "MyAppDisplayName" -PackageDescription "Package exported using PnP Powershell" -PackageCreatedBy "Siddharth Vaghasia" -PackageSourceEnvironment "UAT Environment" +``` +This will export the specified Microsoft Power App from the default Power Platform environment with metadata specified + +### Example 3 +```powershell +Get-PnPPowerPlatformEnvironment | foreach { Get-PnPPowerApp -Environment $_.Name } | foreach { Export-PnPPowerApp -Environment $_.Properties.EnvironmentDetails.Name -Identity $_ -OutPath "C:\Users\user1\Downloads\$($_.Name).zip" } +``` + +This will export all the Microsoft Power Apps available within the tenant from all users from all the available Power Platform environments as a ZIP package for each of them to a local folder C:\Users\user1\Downloads + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. +Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing Get-PnPConnection. + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Environment +The environment which contains the App. + +```yaml +Type: PowerPlatformEnvironmentPipeBind +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +The value of the Name property of a Microsoft Power App that you wish to export + +```yaml +Type: PowerAppPipeBind +Parameter Sets: (All) +Aliases: + +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Force +If specified and the file exported already exists it will be overwritten without confirmation. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -OutPath +Optional file name of the file to export to. If not provided, it will store the ZIP package to the current location from where the cmdlet is being run. + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PackageCreatedBy +The name of the person to be used as the creator of the exported package + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PackageDescription +The description to use in the exported package + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PackageDisplayName +The display name to use in the exported package + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -PackageSourceEnvironment +The name of the source environment from which the exported package was taken + +```yaml +Type: String +Parameter Sets: (All) +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/src/Commands/Model/PowerPlatform/PowerApp/Enums/PowerAppExportStatus.cs b/src/Commands/Model/PowerPlatform/PowerApp/Enums/PowerAppExportStatus.cs new file mode 100644 index 000000000..16ba71a3f --- /dev/null +++ b/src/Commands/Model/PowerPlatform/PowerApp/Enums/PowerAppExportStatus.cs @@ -0,0 +1,23 @@ +namespace PnP.PowerShell.Commands.Model.PowerPlatform.PowerApp.Enums +{ + /// + /// Contains the possible states of a App export request + /// + public enum PowerAppExportStatus + { + /// + /// PowerApp export failed + /// + Failed, + + /// + /// PowerApp exported successfully + /// + Succeeded, + + /// + /// Export in progress + /// + Running + } +} \ No newline at end of file diff --git a/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageError.cs b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageError.cs new file mode 100644 index 000000000..c8bdd4842 --- /dev/null +++ b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageError.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.PowerPlatform.PowerApp +{ + /// + /// Contains the error details when requesting an export of a Flow package + /// + public class PowerAppExportPackageError + { + /// + /// Error code + /// + [JsonPropertyName("code")] + public string Code { get; set; } + + /// + /// Description of the error + /// + [JsonPropertyName("message")] + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageResource.cs b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageResource.cs new file mode 100644 index 000000000..689269898 --- /dev/null +++ b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppExportPackageResource.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.PowerPlatform.PowerApp +{ + /// + /// Contains details on a specific resource in a Flow export request + /// + public class PowerAppExportPackageResource + { + /// + /// Full identifier path of the resource + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// Identifier of the resource + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Type of resource + /// + [JsonPropertyName("type")] + public string Type { get; set; } + + /// + /// Indicator if the resource should be updated or considered a new resource by default on import + /// + [JsonPropertyName("creationType")] + public string CreationType { get; set; } + + /// + /// Additional details on the resource + /// + [JsonPropertyName("details")] + public Dictionary Details { get; set; } + + /// + /// Indicator who can configure the resource + /// + [JsonPropertyName("configurableBy")] + public string ConfigurableBy { get; set; } + + /// + /// Indicator where this resource is located in a hierarchical structure + /// + [JsonPropertyName("hierarchy")] + public string Hierarchy { get; set; } + + /// + /// Indicator if there are dependencies on other resources + /// + [JsonPropertyName("dependsOn")] + public object[] DependsOn { get; set; } + + /// + /// Suggested approach on import + /// + [JsonPropertyName("suggestedCreationType")] + public string SuggestedCreationType { get; set; } + } +} \ No newline at end of file diff --git a/src/Commands/Model/PowerPlatform/PowerApp/PowerAppPackageWrapper.cs b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppPackageWrapper.cs new file mode 100644 index 000000000..90676d6f2 --- /dev/null +++ b/src/Commands/Model/PowerPlatform/PowerApp/PowerAppPackageWrapper.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.PowerPlatform.PowerApp +{ + /// + /// Contains the results of a request to export a Flow package + /// + public class PowerAppPackageWrapper + { + /// + /// Raw state indicating if the Flow export request was successful + /// + [JsonPropertyName("status")] + public string StatusRaw { get; set; } + + /// + /// The status of the export request as an enum + /// + [JsonIgnore] + public Enums.PowerAppExportStatus? Status + { + get { return !string.IsNullOrWhiteSpace(StatusRaw) && Enum.TryParse(StatusRaw, true, out var result) ? result : (Enums.PowerAppExportStatus?)null; } + set { StatusRaw = value.ToString(); } + } + + /// + /// Contains the resource identifiers + /// + [JsonPropertyName("baseResourceIds")] + public string[] BaseResourceIds { get; set; } + + /// + /// List with resources contained in the export + /// + [JsonPropertyName("resources")] + public Dictionary Resources { get; set; } + + /// + /// Array with errors generated when trying to export the resource + /// + [JsonPropertyName("errors")] + public PowerAppExportPackageError[] Errors{ get; set; } + } +} \ No newline at end of file diff --git a/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs b/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs new file mode 100644 index 000000000..fcbc2468b --- /dev/null +++ b/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs @@ -0,0 +1,181 @@ +using PnP.PowerShell.Commands.Attributes; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Base.PipeBinds; +using PnP.PowerShell.Commands.Utilities.REST; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Management.Automation; +using System.Net.Http; +using System.Text.Json; +using System.Threading; + +namespace PnP.PowerShell.Commands.PowerPlatform.PowerApps +{ + [Cmdlet(VerbsData.Export, "PnPPowerApp")] + [RequiredMinimalApiPermissions("https://management.azure.com/.default")] + public class ExportPowerApp : PnPAzureManagementApiCmdlet + { + + [Parameter(Mandatory = true)] + + public PowerPlatformEnvironmentPipeBind Environment; + + [Parameter(Mandatory = true)] + public PowerAppPipeBind Identity; + + [Parameter(Mandatory = false)] + public string PackageDisplayName; + + [Parameter(Mandatory = false)] + public string PackageDescription; + + [Parameter(Mandatory = false)] + public string PackageCreatedBy; + + [Parameter(Mandatory = false)] + public string PackageSourceEnvironment; + + [Parameter(Mandatory = false)] + public string OutPath; + + [Parameter(Mandatory = false)] + public SwitchParameter Force; + + protected override void ExecuteCmdlet() + { + if (ParameterSpecified(nameof(OutPath))) + { + if (!System.IO.Path.IsPathRooted(OutPath)) + { + OutPath = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutPath); + } + if (System.IO.Directory.Exists(OutPath)) + { + throw new PSArgumentException("Please specify a folder including a filename"); + } + if (System.IO.File.Exists(OutPath)) + { + if (!Force && !ShouldContinue($"File '{OutPath}' exists. Overwrite?", "Export App")) + { + // Exit cmdlet + return; + } + } + } + + var environmentName = Environment.GetName(); + var appName = Identity.GetName(); + + var postData = new + { + baseResourceIds = new[] { + $"/providers/Microsoft.PowerApps/apps/{appName}" + } + }; + var wrapper = RestHelper.PostAsync(Connection.HttpClient, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/listPackageResources?api-version=2016-11-01", AccessToken, payload: postData).GetAwaiter().GetResult(); + + if (wrapper.Status == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded) + { + foreach (var resource in wrapper.Resources) + { + if (resource.Value.Type == "Microsoft.PowerApps/apps") + { + resource.Value.SuggestedCreationType = "Update"; + } + } + var exportPostData = new + { + includedResourceIds = new[] + { + $"/providers/Microsoft.PowerApps/apps/{appName}" + }, + details = new + { + displayName = PackageDisplayName, + description = PackageDescription, + creator = PackageCreatedBy, + sourceEnvironment = PackageSourceEnvironment + }, + resources = wrapper.Resources + }; + + var responseHeader = RestHelper.PostAsyncGetResponseHeader(Connection.HttpClient, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/exportPackage?api-version=2016-11-01", AccessToken, payload: exportPostData).GetAwaiter().GetResult(); + + var packageLink = getPackageLink(Convert.ToString(responseHeader.Location)); + using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, packageLink)) + { + requestMessage.Version = new Version(2, 0); + //requestMessage.Headers.Add("Authorization", $"Bearer {AccessToken}"); + var fileresponse = Connection.HttpClient.SendAsync(requestMessage).GetAwaiter().GetResult(); + var byteArray = fileresponse.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); + var fileName = string.Empty; + if (ParameterSpecified(nameof(OutPath))) + { + if (!System.IO.Path.IsPathRooted(OutPath)) + { + OutPath = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutPath); + } + fileName = OutPath; + } + else + { + fileName = new System.Text.RegularExpressions.Regex("([^\\/]+\\.zip)").Match(packageLink).Value; + fileName = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, fileName); + } + + System.IO.File.WriteAllBytes(fileName, byteArray); + var returnObject = new PSObject(); + returnObject.Properties.Add(new PSNoteProperty("Filename", fileName)); + WriteObject(returnObject); + } + + } + else + { + // Errors have been reported in the export request result + foreach (var error in wrapper.Errors) + { + WriteVerbose($"Export failed for {appName} with error {error.Code}: {error.Message}"); + } + } + } + private string getPackageLink(string location) + { + var status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running; + var packageLink = ""; + if (location != null) + { + do + { + var runningresponse = RestHelper.GetAsync(Connection.HttpClient, location, AccessToken).GetAwaiter().GetResult(); + + if (runningresponse.TryGetProperty("properties", out JsonElement properties)) + { + if (properties.TryGetProperty("status", out JsonElement runningstatusElement)) + { + if (runningstatusElement.GetString() == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded.ToString()) + { + status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded; + if (properties.TryGetProperty("packageLink", out JsonElement packageLinkElement)) + { + if (packageLinkElement.TryGetProperty("value", out JsonElement valueElement)) + { + packageLink = valueElement.GetString(); + } + } + } + else + { + //if status is still running, sleep the thread for 3 seconds + Thread.Sleep(3000); + } + } + } + } while (status == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running); + } + return packageLink; + } + } +} diff --git a/src/Commands/Utilities/REST/RestHelper.cs b/src/Commands/Utilities/REST/RestHelper.cs index 4513739b9..b159e78df 100644 --- a/src/Commands/Utilities/REST/RestHelper.cs +++ b/src/Commands/Utilities/REST/RestHelper.cs @@ -289,6 +289,22 @@ public static async Task PostAsync(HttpClient httpClient, string url, stri return default(T); } + public static async Task PostAsyncGetResponseHeader(HttpClient httpClient, string url, string accessToken, object payload, bool camlCasePolicy = true, string accept = "application/json") + { + HttpRequestMessage message = null; + if (payload != null) + { + var content = new StringContent(JsonSerializer.Serialize(payload, new JsonSerializerOptions { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull })); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + message = GetMessage(url, HttpMethod.Post, accessToken, accept, content); + } + else + { + message = GetMessage(url, HttpMethod.Post, accessToken, accept); + } + return await SendMessageAsyncGetResponseHeader(httpClient, message); + } + public static async Task PostAsync(HttpClient httpClient, string url, ClientContext clientContext, object payload, bool camlCasePolicy = true) @@ -633,6 +649,28 @@ private static async Task SendMessageAsync(HttpClient httpClient, HttpRe } } + private static async Task SendMessageAsyncGetResponseHeader(HttpClient httpClient, HttpRequestMessage message) + { + var response = await httpClient.SendAsync(message); + while (response.StatusCode == (HttpStatusCode)429) + { + // throttled + var retryAfter = response.Headers.RetryAfter; + await Task.Delay(retryAfter.Delta.Value.Seconds * 1000); + response = await httpClient.SendAsync(CloneMessage(message)); + } + if (response.IsSuccessStatusCode) + { + return response.Headers; + } + else + { + var errorContent = await response.Content.ReadAsStringAsync(); + throw new HttpRequestException(errorContent); + } + } + + private static HttpRequestMessage CloneMessage(HttpRequestMessage req) { HttpRequestMessage clone = new HttpRequestMessage(req.Method, req.RequestUri); From 19d866782367ba619fff039125588b320e3623e4 Mon Sep 17 00:00:00 2001 From: Siddharth Vaghasia Date: Tue, 4 Jul 2023 14:33:09 +0530 Subject: [PATCH 2/3] updated as per review comments. --- .../Environment/PowerPlatformConnector.cs | 403 ++++++++++++++++++ .../Environment/GetPowerPlatformConnectors.cs | 68 +++ .../PowerPlatform/PowerApps/ExportPowerApp.cs | 88 +--- src/Commands/Utilities/PowerAppsUtility.cs | 100 +++++ 4 files changed, 587 insertions(+), 72 deletions(-) create mode 100644 src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs create mode 100644 src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs create mode 100644 src/Commands/Utilities/PowerAppsUtility.cs diff --git a/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs b/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs new file mode 100644 index 000000000..76a7760b9 --- /dev/null +++ b/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs @@ -0,0 +1,403 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.PowerPlatform.Environment +{ + public class PowerPlatformConnector + { + + [JsonPropertyName("name")] + public string name { get; set; } + + [JsonPropertyName("id")] + public string id { get; set; } + + [JsonPropertyName("type")] + public string type { get; set; } + + [JsonPropertyName("properties")] + public Properties properties { get; set; } + + + public class ApiDefinitions + { + [JsonPropertyName("originalSwaggerUrl")] + public string originalSwaggerUrl { get; set; } + + [JsonPropertyName("modifiedSwaggerUrl")] + public string modifiedSwaggerUrl { get; set; } + } + + public class AuthorizationUrl + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class BackendService + { + [JsonPropertyName("serviceUrl")] + public string serviceUrl { get; set; } + } + + public class ConnectionParameters + { + [JsonPropertyName("token")] + public Token token { get; set; } + + [JsonPropertyName("token:TenantId")] + public TokenTenantId tokenTenantId { get; set; } + } + + public class Constraints + { + [JsonPropertyName("required")] + public string required { get; set; } + + [JsonPropertyName("hidden")] + public string hidden { get; set; } + } + + public class Contact + { + } + + public class CreatedBy + { + [JsonPropertyName("id")] + public string id { get; set; } + + [JsonPropertyName("displayName")] + public string displayName { get; set; } + + [JsonPropertyName("email")] + public string email { get; set; } + + [JsonPropertyName("type")] + public string type { get; set; } + + [JsonPropertyName("tenantId")] + public string tenantId { get; set; } + + [JsonPropertyName("userPrincipalName")] + public string userPrincipalName { get; set; } + } + + public class CustomParameters + { + [JsonPropertyName("loginUri")] + public LoginUri loginUri { get; set; } + + [JsonPropertyName("tenantId")] + public TenantId tenantId { get; set; } + + [JsonPropertyName("resourceUri")] + public ResourceUri resourceUri { get; set; } + + [JsonPropertyName("authorizationUrl")] + public AuthorizationUrl authorizationUrl { get; set; } + + [JsonPropertyName("tokenUrl")] + public TokenUrl tokenUrl { get; set; } + + [JsonPropertyName("refreshUrl")] + public RefreshUrl refreshUrl { get; set; } + + [JsonPropertyName("enableOnbehalfOfLogin")] + public EnableOnbehalfOfLogin enableOnbehalfOfLogin { get; set; } + } + + public class EnableOnbehalfOfLogin + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class Environment + { + [JsonPropertyName("id")] + public string id { get; set; } + + [JsonPropertyName("name")] + public string name { get; set; } + } + + public class License + { + } + + public class LoginUri + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class Metadata + { + [JsonPropertyName("sourceType")] + public string sourceType { get; set; } + + [JsonPropertyName("source")] + public string source { get; set; } + + [JsonPropertyName("brandColor")] + public string brandColor { get; set; } + + [JsonPropertyName("contact")] + public Contact contact { get; set; } + + [JsonPropertyName("license")] + public License license { get; set; } + + [JsonPropertyName("publisherUrl")] + public object publisherUrl { get; set; } + + [JsonPropertyName("serviceUrl")] + public object serviceUrl { get; set; } + + [JsonPropertyName("documentationUrl")] + public object documentationUrl { get; set; } + + [JsonPropertyName("environmentName")] + public string environmentName { get; set; } + + [JsonPropertyName("xrmConnectorId")] + public object xrmConnectorId { get; set; } + + [JsonPropertyName("almMode")] + public string almMode { get; set; } + + [JsonPropertyName("useNewApimVersion")] + public bool useNewApimVersion { get; set; } + + [JsonPropertyName("createdBy")] + public string createdBy { get; set; } + + [JsonPropertyName("modifiedBy")] + public string modifiedBy { get; set; } + + [JsonPropertyName("allowSharing")] + public bool allowSharing { get; set; } + + [JsonPropertyName("parameters")] + public Parameters parameters { get; set; } + } + + public class ModifiedBy + { + [JsonPropertyName("id")] + public string id { get; set; } + + [JsonPropertyName("displayName")] + public string displayName { get; set; } + + [JsonPropertyName("email")] + public string email { get; set; } + + [JsonPropertyName("type")] + public string type { get; set; } + + [JsonPropertyName("tenantId")] + public string tenantId { get; set; } + + [JsonPropertyName("userPrincipalName")] + public string userPrincipalName { get; set; } + } + + public class OAuthSettings + { + [JsonPropertyName("identityProvider")] + public string identityProvider { get; set; } + + [JsonPropertyName("clientId")] + public string clientId { get; set; } + + [JsonPropertyName("scopes")] + public List scopes { get; set; } + + [JsonPropertyName("redirectMode")] + public string redirectMode { get; set; } + + [JsonPropertyName("redirectUrl")] + public string redirectUrl { get; set; } + + [JsonPropertyName("properties")] + public Properties properties { get; set; } + + [JsonPropertyName("customParameters")] + public CustomParameters customParameters { get; set; } + } + + public class Parameters + { + [JsonPropertyName("x-ms-apimTemplateParameter.name")] + public string xmsapimTemplateParametername { get; set; } + + [JsonPropertyName("x-ms-apimTemplateParameter.value")] + public string xmsapimTemplateParametervalue { get; set; } + + [JsonPropertyName("x-ms-apimTemplateParameter.existsAction")] + public string xmsapimTemplateParameterexistsAction { get; set; } + + [JsonPropertyName("x-ms-apimTemplate-policySection")] + public string xmsapimTemplatepolicySection { get; set; } + } + + public class PolicyTemplateInstance + { + [JsonPropertyName("templateId")] + public string templateId { get; set; } + + [JsonPropertyName("title")] + public string title { get; set; } + + [JsonPropertyName("parameters")] + public Parameters parameters { get; set; } + } + + public class Properties + { + [JsonPropertyName("displayName")] + public string displayName { get; set; } + + [JsonPropertyName("iconUri")] + public string iconUri { get; set; } + + [JsonPropertyName("iconBrandColor")] + public string iconBrandColor { get; set; } + + [JsonPropertyName("contact")] + public Contact contact { get; set; } + + [JsonPropertyName("license")] + public License license { get; set; } + + [JsonPropertyName("apiEnvironment")] + public string apiEnvironment { get; set; } + + [JsonPropertyName("isCustomApi")] + public bool isCustomApi { get; set; } + + [JsonPropertyName("connectionParameters")] + public ConnectionParameters connectionParameters { get; set; } + + [JsonPropertyName("runtimeUrls")] + public List runtimeUrls { get; set; } + + [JsonPropertyName("primaryRuntimeUrl")] + public string primaryRuntimeUrl { get; set; } + + [JsonPropertyName("metadata")] + public Metadata metadata { get; set; } + + [JsonPropertyName("capabilities")] + public List capabilities { get; set; } + + [JsonPropertyName("description")] + public string description { get; set; } + + [JsonPropertyName("apiDefinitions")] + public ApiDefinitions apiDefinitions { get; set; } + + [JsonPropertyName("backendService")] + public BackendService backendService { get; set; } + + [JsonPropertyName("createdBy")] + public CreatedBy createdBy { get; set; } + + [JsonPropertyName("modifiedBy")] + public ModifiedBy modifiedBy { get; set; } + + [JsonPropertyName("createdTime")] + public DateTimeOffset createdTime { get; set; } + + [JsonPropertyName("changedTime")] + public DateTimeOffset changedTime { get; set; } + + [JsonPropertyName("environment")] + public Environment environment { get; set; } + + [JsonPropertyName("tier")] + public string tier { get; set; } + + [JsonPropertyName("publisher")] + public string publisher { get; set; } + + [JsonPropertyName("almMode")] + public string almMode { get; set; } + + [JsonPropertyName("parameters")] + public Parameters parameters { get; set; } + + [JsonPropertyName("policyTemplateInstances")] + public List policyTemplateInstances { get; set; } + + [JsonPropertyName("IsFirstParty")] + public string IsFirstParty { get; set; } + + [JsonPropertyName("AzureActiveDirectoryResourceId")] + public string AzureActiveDirectoryResourceId { get; set; } + + [JsonPropertyName("IsOnbehalfofLoginSupported")] + public bool IsOnbehalfofLoginSupported { get; set; } + } + + public class RefreshUrl + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class ResourceUri + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class TenantId + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class Token + { + [JsonPropertyName("type")] + public string type { get; set; } + + [JsonPropertyName("oAuthSettings")] + public OAuthSettings oAuthSettings { get; set; } + } + + public class TokenTenantId + { + [JsonPropertyName("type")] + public string type { get; set; } + + [JsonPropertyName("metadata")] + public Metadata metadata { get; set; } + + [JsonPropertyName("uiDefinition")] + public UiDefinition uiDefinition { get; set; } + } + + public class TokenUrl + { + [JsonPropertyName("value")] + public string value { get; set; } + } + + public class UiDefinition + { + [JsonPropertyName("constraints")] + public Constraints constraints { get; set; } + } + + + + + + + } +} diff --git a/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs b/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs new file mode 100644 index 000000000..592abf71d --- /dev/null +++ b/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs @@ -0,0 +1,68 @@ +using PnP.PowerShell.Commands.Attributes; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Utilities.REST; +using System; +using System.Management.Automation; +using System.Linq; +using PnP.PowerShell.Commands.Base.PipeBinds; + + +namespace PnP.PowerShell.Commands.PowerPlatform.Environment +{ + [Cmdlet(VerbsCommon.Get, "PnPPowerPlatformConnectors")] + public class GetPowerPlatformConnectors : PnPAzureManagementApiCmdlet + { + + [Parameter(Mandatory = false, ValueFromPipeline = true)] + public PowerPlatformEnvironmentPipeBind Environment; + + [Parameter(Mandatory = false)] + public SwitchParameter AsAdmin; + + [Parameter(Mandatory = false)] + public PowerAppPipeBind Identity; // TODO + + protected override void ExecuteCmdlet() + { + string environmentName = null; + if (ParameterSpecified(nameof(Environment))) + { + environmentName = Environment.GetName(); + + WriteVerbose($"Using environment as provided '{environmentName}'"); + } + else + { + var environments = GraphHelper.GetResultCollectionAsync(Connection, "https://management.azure.com/providers/Microsoft.ProcessSimple/environments?api-version=2016-11-01", AccessToken).GetAwaiter().GetResult(); + environmentName = environments.FirstOrDefault(e => e.Properties.IsDefault.HasValue && e.Properties.IsDefault == true)?.Name; + + if (string.IsNullOrEmpty(environmentName)) + { + throw new Exception($"No default environment found, please pass in a specific environment name using the {nameof(Environment)} parameter"); + } + + WriteVerbose($"Using default environment as retrieved '{environmentName}'"); + } + + //TODO + if (ParameterSpecified(nameof(Identity))) + { + var appName = Identity.GetName(); + + WriteVerbose($"Retrieving specific PowerApp with the provided name '{appName}' within the environment '{environmentName}'"); + + var result = GraphHelper.GetAsync(Connection, $"https://api.powerapps.com/providers/Microsoft.PowerApps{(AsAdmin ? "/scopes/admin/environments/" + environmentName : "")}/apps/{appName}?api-version=2016-11-01", AccessToken).GetAwaiter().GetResult(); + + WriteObject(result, false); + } + else + { + WriteVerbose($"Retrieving all Connectors within environment '{environmentName}'"); + + var connectors = GraphHelper.GetResultCollectionAsync(Connection, $"https://api.powerapps.com/providers/Microsoft.PowerApps/apis?api-version=2016-11-01&$filter=environment eq '{environmentName}' and isCustomApi eq 'True'", AccessToken).GetAwaiter().GetResult(); + WriteObject(connectors, true); + } + + } + } +} \ No newline at end of file diff --git a/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs b/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs index fcbc2468b..1f47dd593 100644 --- a/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs +++ b/src/Commands/PowerPlatform/PowerApps/ExportPowerApp.cs @@ -10,6 +10,7 @@ using System.Net.Http; using System.Text.Json; using System.Threading; +using PnP.PowerShell.Commands.Utilities; namespace PnP.PowerShell.Commands.PowerPlatform.PowerApps { @@ -68,14 +69,8 @@ protected override void ExecuteCmdlet() var environmentName = Environment.GetName(); var appName = Identity.GetName(); - var postData = new - { - baseResourceIds = new[] { - $"/providers/Microsoft.PowerApps/apps/{appName}" - } - }; - var wrapper = RestHelper.PostAsync(Connection.HttpClient, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/listPackageResources?api-version=2016-11-01", AccessToken, payload: postData).GetAwaiter().GetResult(); - + var wrapper = PowerAppsUtility.GetWrapper(Connection.HttpClient, environmentName, AccessToken, appName).GetAwaiter().GetResult(); + if (wrapper.Status == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded) { foreach (var resource in wrapper.Resources) @@ -85,31 +80,17 @@ protected override void ExecuteCmdlet() resource.Value.SuggestedCreationType = "Update"; } } - var exportPostData = new - { - includedResourceIds = new[] - { - $"/providers/Microsoft.PowerApps/apps/{appName}" - }, - details = new - { - displayName = PackageDisplayName, - description = PackageDescription, - creator = PackageCreatedBy, - sourceEnvironment = PackageSourceEnvironment - }, - resources = wrapper.Resources - }; - - var responseHeader = RestHelper.PostAsyncGetResponseHeader(Connection.HttpClient, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/exportPackage?api-version=2016-11-01", AccessToken, payload: exportPostData).GetAwaiter().GetResult(); - - var packageLink = getPackageLink(Convert.ToString(responseHeader.Location)); - using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, packageLink)) - { - requestMessage.Version = new Version(2, 0); - //requestMessage.Headers.Add("Authorization", $"Bearer {AccessToken}"); - var fileresponse = Connection.HttpClient.SendAsync(requestMessage).GetAwaiter().GetResult(); - var byteArray = fileresponse.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); + var objectDetails = new { + displayName = PackageDisplayName, + description = PackageDescription, + creator = PackageCreatedBy, + sourceEnvironment = PackageSourceEnvironment + }; + var responseHeader = PowerAppsUtility.GetResponseHeader(Connection.HttpClient, environmentName,AccessToken, appName, wrapper, objectDetails); + + + var packageLink = PowerAppsUtility.GetPackageLink(Connection.HttpClient,Convert.ToString(responseHeader.Location),AccessToken); + var getFileByteArray = PowerAppsUtility.GetFileByteArray(Connection.HttpClient, packageLink, AccessToken); var fileName = string.Empty; if (ParameterSpecified(nameof(OutPath))) { @@ -125,13 +106,11 @@ protected override void ExecuteCmdlet() fileName = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, fileName); } - System.IO.File.WriteAllBytes(fileName, byteArray); + System.IO.File.WriteAllBytes(fileName, getFileByteArray); var returnObject = new PSObject(); returnObject.Properties.Add(new PSNoteProperty("Filename", fileName)); WriteObject(returnObject); } - - } else { // Errors have been reported in the export request result @@ -141,41 +120,6 @@ protected override void ExecuteCmdlet() } } } - private string getPackageLink(string location) - { - var status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running; - var packageLink = ""; - if (location != null) - { - do - { - var runningresponse = RestHelper.GetAsync(Connection.HttpClient, location, AccessToken).GetAwaiter().GetResult(); - - if (runningresponse.TryGetProperty("properties", out JsonElement properties)) - { - if (properties.TryGetProperty("status", out JsonElement runningstatusElement)) - { - if (runningstatusElement.GetString() == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded.ToString()) - { - status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded; - if (properties.TryGetProperty("packageLink", out JsonElement packageLinkElement)) - { - if (packageLinkElement.TryGetProperty("value", out JsonElement valueElement)) - { - packageLink = valueElement.GetString(); - } - } - } - else - { - //if status is still running, sleep the thread for 3 seconds - Thread.Sleep(3000); - } - } - } - } while (status == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running); - } - return packageLink; - } + } } diff --git a/src/Commands/Utilities/PowerAppsUtility.cs b/src/Commands/Utilities/PowerAppsUtility.cs new file mode 100644 index 000000000..773a97a48 --- /dev/null +++ b/src/Commands/Utilities/PowerAppsUtility.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Utilities.REST; + +namespace PnP.PowerShell.Commands.Utilities +{ + internal static class PowerAppsUtility + { + internal static async Task GetWrapper(HttpClient connection, string environmentName, string accessToken, string appName) + { + var postData = new + { + baseResourceIds = new[] { + $"/providers/Microsoft.PowerApps/apps/{appName}" + } + }; + + var wrapper = await RestHelper.PostAsync(connection, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/listPackageResources?api-version=2016-11-01", accessToken, payload: postData); + + + return wrapper; + } + + internal static HttpResponseHeaders GetResponseHeader(HttpClient connection, string environmentName, string accessToken, string appName,Model.PowerPlatform.PowerApp.PowerAppPackageWrapper wrapper, object details) + { + var exportPostData = new + { + includedResourceIds = new[] + { + $"/providers/Microsoft.PowerApps/apps/{appName}" + }, + details = details, + resources = wrapper.Resources + }; + + var responseHeader = RestHelper.PostAsyncGetResponseHeader(connection, $"https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/environments/{environmentName}/exportPackage?api-version=2016-11-01", accessToken, payload: exportPostData).GetAwaiter().GetResult(); + + + return responseHeader; + } + + internal static string GetPackageLink(HttpClient connection,string location,string accessToken) + { + var status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running; + var packageLink = ""; + if (location != null) + { + do + { + var runningresponse = RestHelper.GetAsync(connection, location, accessToken).GetAwaiter().GetResult(); + + if (runningresponse.TryGetProperty("properties", out JsonElement properties)) + { + if (properties.TryGetProperty("status", out JsonElement runningstatusElement)) + { + if (runningstatusElement.GetString() == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded.ToString()) + { + status = Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Succeeded; + if (properties.TryGetProperty("packageLink", out JsonElement packageLinkElement)) + { + if (packageLinkElement.TryGetProperty("value", out JsonElement valueElement)) + { + packageLink = valueElement.GetString(); + } + } + } + else + { + //if status is still running, sleep the thread for 3 seconds + Thread.Sleep(3000); + } + } + } + } while (status == Model.PowerPlatform.PowerApp.Enums.PowerAppExportStatus.Running); + } + return packageLink; + } + + internal static byte[] GetFileByteArray(HttpClient connection, string packageLink, string accessToken) + { + using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, packageLink)) + { + requestMessage.Version = new Version(2, 0); + //requestMessage.Headers.Add("Authorization", $"Bearer {AccessToken}"); + var fileresponse = connection.SendAsync(requestMessage).GetAwaiter().GetResult(); + var byteArray = fileresponse.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); + return byteArray; + } + + } + } +} From aacbceedf7d8be02fd5189ba253904facf31f724 Mon Sep 17 00:00:00 2001 From: Siddharth Vaghasia Date: Wed, 5 Jul 2023 18:53:42 +0530 Subject: [PATCH 3/3] removed files related to GetConnectors command --- .../Environment/PowerPlatformConnector.cs | 403 ------------------ .../Environment/GetPowerPlatformConnectors.cs | 68 --- 2 files changed, 471 deletions(-) delete mode 100644 src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs delete mode 100644 src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs diff --git a/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs b/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs deleted file mode 100644 index 76a7760b9..000000000 --- a/src/Commands/Model/PowerPlatform/Environment/PowerPlatformConnector.cs +++ /dev/null @@ -1,403 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json.Serialization; - -namespace PnP.PowerShell.Commands.Model.PowerPlatform.Environment -{ - public class PowerPlatformConnector - { - - [JsonPropertyName("name")] - public string name { get; set; } - - [JsonPropertyName("id")] - public string id { get; set; } - - [JsonPropertyName("type")] - public string type { get; set; } - - [JsonPropertyName("properties")] - public Properties properties { get; set; } - - - public class ApiDefinitions - { - [JsonPropertyName("originalSwaggerUrl")] - public string originalSwaggerUrl { get; set; } - - [JsonPropertyName("modifiedSwaggerUrl")] - public string modifiedSwaggerUrl { get; set; } - } - - public class AuthorizationUrl - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class BackendService - { - [JsonPropertyName("serviceUrl")] - public string serviceUrl { get; set; } - } - - public class ConnectionParameters - { - [JsonPropertyName("token")] - public Token token { get; set; } - - [JsonPropertyName("token:TenantId")] - public TokenTenantId tokenTenantId { get; set; } - } - - public class Constraints - { - [JsonPropertyName("required")] - public string required { get; set; } - - [JsonPropertyName("hidden")] - public string hidden { get; set; } - } - - public class Contact - { - } - - public class CreatedBy - { - [JsonPropertyName("id")] - public string id { get; set; } - - [JsonPropertyName("displayName")] - public string displayName { get; set; } - - [JsonPropertyName("email")] - public string email { get; set; } - - [JsonPropertyName("type")] - public string type { get; set; } - - [JsonPropertyName("tenantId")] - public string tenantId { get; set; } - - [JsonPropertyName("userPrincipalName")] - public string userPrincipalName { get; set; } - } - - public class CustomParameters - { - [JsonPropertyName("loginUri")] - public LoginUri loginUri { get; set; } - - [JsonPropertyName("tenantId")] - public TenantId tenantId { get; set; } - - [JsonPropertyName("resourceUri")] - public ResourceUri resourceUri { get; set; } - - [JsonPropertyName("authorizationUrl")] - public AuthorizationUrl authorizationUrl { get; set; } - - [JsonPropertyName("tokenUrl")] - public TokenUrl tokenUrl { get; set; } - - [JsonPropertyName("refreshUrl")] - public RefreshUrl refreshUrl { get; set; } - - [JsonPropertyName("enableOnbehalfOfLogin")] - public EnableOnbehalfOfLogin enableOnbehalfOfLogin { get; set; } - } - - public class EnableOnbehalfOfLogin - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class Environment - { - [JsonPropertyName("id")] - public string id { get; set; } - - [JsonPropertyName("name")] - public string name { get; set; } - } - - public class License - { - } - - public class LoginUri - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class Metadata - { - [JsonPropertyName("sourceType")] - public string sourceType { get; set; } - - [JsonPropertyName("source")] - public string source { get; set; } - - [JsonPropertyName("brandColor")] - public string brandColor { get; set; } - - [JsonPropertyName("contact")] - public Contact contact { get; set; } - - [JsonPropertyName("license")] - public License license { get; set; } - - [JsonPropertyName("publisherUrl")] - public object publisherUrl { get; set; } - - [JsonPropertyName("serviceUrl")] - public object serviceUrl { get; set; } - - [JsonPropertyName("documentationUrl")] - public object documentationUrl { get; set; } - - [JsonPropertyName("environmentName")] - public string environmentName { get; set; } - - [JsonPropertyName("xrmConnectorId")] - public object xrmConnectorId { get; set; } - - [JsonPropertyName("almMode")] - public string almMode { get; set; } - - [JsonPropertyName("useNewApimVersion")] - public bool useNewApimVersion { get; set; } - - [JsonPropertyName("createdBy")] - public string createdBy { get; set; } - - [JsonPropertyName("modifiedBy")] - public string modifiedBy { get; set; } - - [JsonPropertyName("allowSharing")] - public bool allowSharing { get; set; } - - [JsonPropertyName("parameters")] - public Parameters parameters { get; set; } - } - - public class ModifiedBy - { - [JsonPropertyName("id")] - public string id { get; set; } - - [JsonPropertyName("displayName")] - public string displayName { get; set; } - - [JsonPropertyName("email")] - public string email { get; set; } - - [JsonPropertyName("type")] - public string type { get; set; } - - [JsonPropertyName("tenantId")] - public string tenantId { get; set; } - - [JsonPropertyName("userPrincipalName")] - public string userPrincipalName { get; set; } - } - - public class OAuthSettings - { - [JsonPropertyName("identityProvider")] - public string identityProvider { get; set; } - - [JsonPropertyName("clientId")] - public string clientId { get; set; } - - [JsonPropertyName("scopes")] - public List scopes { get; set; } - - [JsonPropertyName("redirectMode")] - public string redirectMode { get; set; } - - [JsonPropertyName("redirectUrl")] - public string redirectUrl { get; set; } - - [JsonPropertyName("properties")] - public Properties properties { get; set; } - - [JsonPropertyName("customParameters")] - public CustomParameters customParameters { get; set; } - } - - public class Parameters - { - [JsonPropertyName("x-ms-apimTemplateParameter.name")] - public string xmsapimTemplateParametername { get; set; } - - [JsonPropertyName("x-ms-apimTemplateParameter.value")] - public string xmsapimTemplateParametervalue { get; set; } - - [JsonPropertyName("x-ms-apimTemplateParameter.existsAction")] - public string xmsapimTemplateParameterexistsAction { get; set; } - - [JsonPropertyName("x-ms-apimTemplate-policySection")] - public string xmsapimTemplatepolicySection { get; set; } - } - - public class PolicyTemplateInstance - { - [JsonPropertyName("templateId")] - public string templateId { get; set; } - - [JsonPropertyName("title")] - public string title { get; set; } - - [JsonPropertyName("parameters")] - public Parameters parameters { get; set; } - } - - public class Properties - { - [JsonPropertyName("displayName")] - public string displayName { get; set; } - - [JsonPropertyName("iconUri")] - public string iconUri { get; set; } - - [JsonPropertyName("iconBrandColor")] - public string iconBrandColor { get; set; } - - [JsonPropertyName("contact")] - public Contact contact { get; set; } - - [JsonPropertyName("license")] - public License license { get; set; } - - [JsonPropertyName("apiEnvironment")] - public string apiEnvironment { get; set; } - - [JsonPropertyName("isCustomApi")] - public bool isCustomApi { get; set; } - - [JsonPropertyName("connectionParameters")] - public ConnectionParameters connectionParameters { get; set; } - - [JsonPropertyName("runtimeUrls")] - public List runtimeUrls { get; set; } - - [JsonPropertyName("primaryRuntimeUrl")] - public string primaryRuntimeUrl { get; set; } - - [JsonPropertyName("metadata")] - public Metadata metadata { get; set; } - - [JsonPropertyName("capabilities")] - public List capabilities { get; set; } - - [JsonPropertyName("description")] - public string description { get; set; } - - [JsonPropertyName("apiDefinitions")] - public ApiDefinitions apiDefinitions { get; set; } - - [JsonPropertyName("backendService")] - public BackendService backendService { get; set; } - - [JsonPropertyName("createdBy")] - public CreatedBy createdBy { get; set; } - - [JsonPropertyName("modifiedBy")] - public ModifiedBy modifiedBy { get; set; } - - [JsonPropertyName("createdTime")] - public DateTimeOffset createdTime { get; set; } - - [JsonPropertyName("changedTime")] - public DateTimeOffset changedTime { get; set; } - - [JsonPropertyName("environment")] - public Environment environment { get; set; } - - [JsonPropertyName("tier")] - public string tier { get; set; } - - [JsonPropertyName("publisher")] - public string publisher { get; set; } - - [JsonPropertyName("almMode")] - public string almMode { get; set; } - - [JsonPropertyName("parameters")] - public Parameters parameters { get; set; } - - [JsonPropertyName("policyTemplateInstances")] - public List policyTemplateInstances { get; set; } - - [JsonPropertyName("IsFirstParty")] - public string IsFirstParty { get; set; } - - [JsonPropertyName("AzureActiveDirectoryResourceId")] - public string AzureActiveDirectoryResourceId { get; set; } - - [JsonPropertyName("IsOnbehalfofLoginSupported")] - public bool IsOnbehalfofLoginSupported { get; set; } - } - - public class RefreshUrl - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class ResourceUri - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class TenantId - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class Token - { - [JsonPropertyName("type")] - public string type { get; set; } - - [JsonPropertyName("oAuthSettings")] - public OAuthSettings oAuthSettings { get; set; } - } - - public class TokenTenantId - { - [JsonPropertyName("type")] - public string type { get; set; } - - [JsonPropertyName("metadata")] - public Metadata metadata { get; set; } - - [JsonPropertyName("uiDefinition")] - public UiDefinition uiDefinition { get; set; } - } - - public class TokenUrl - { - [JsonPropertyName("value")] - public string value { get; set; } - } - - public class UiDefinition - { - [JsonPropertyName("constraints")] - public Constraints constraints { get; set; } - } - - - - - - - } -} diff --git a/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs b/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs deleted file mode 100644 index 592abf71d..000000000 --- a/src/Commands/PowerPlatform/Environment/GetPowerPlatformConnectors.cs +++ /dev/null @@ -1,68 +0,0 @@ -using PnP.PowerShell.Commands.Attributes; -using PnP.PowerShell.Commands.Base; -using PnP.PowerShell.Commands.Utilities.REST; -using System; -using System.Management.Automation; -using System.Linq; -using PnP.PowerShell.Commands.Base.PipeBinds; - - -namespace PnP.PowerShell.Commands.PowerPlatform.Environment -{ - [Cmdlet(VerbsCommon.Get, "PnPPowerPlatformConnectors")] - public class GetPowerPlatformConnectors : PnPAzureManagementApiCmdlet - { - - [Parameter(Mandatory = false, ValueFromPipeline = true)] - public PowerPlatformEnvironmentPipeBind Environment; - - [Parameter(Mandatory = false)] - public SwitchParameter AsAdmin; - - [Parameter(Mandatory = false)] - public PowerAppPipeBind Identity; // TODO - - protected override void ExecuteCmdlet() - { - string environmentName = null; - if (ParameterSpecified(nameof(Environment))) - { - environmentName = Environment.GetName(); - - WriteVerbose($"Using environment as provided '{environmentName}'"); - } - else - { - var environments = GraphHelper.GetResultCollectionAsync(Connection, "https://management.azure.com/providers/Microsoft.ProcessSimple/environments?api-version=2016-11-01", AccessToken).GetAwaiter().GetResult(); - environmentName = environments.FirstOrDefault(e => e.Properties.IsDefault.HasValue && e.Properties.IsDefault == true)?.Name; - - if (string.IsNullOrEmpty(environmentName)) - { - throw new Exception($"No default environment found, please pass in a specific environment name using the {nameof(Environment)} parameter"); - } - - WriteVerbose($"Using default environment as retrieved '{environmentName}'"); - } - - //TODO - if (ParameterSpecified(nameof(Identity))) - { - var appName = Identity.GetName(); - - WriteVerbose($"Retrieving specific PowerApp with the provided name '{appName}' within the environment '{environmentName}'"); - - var result = GraphHelper.GetAsync(Connection, $"https://api.powerapps.com/providers/Microsoft.PowerApps{(AsAdmin ? "/scopes/admin/environments/" + environmentName : "")}/apps/{appName}?api-version=2016-11-01", AccessToken).GetAwaiter().GetResult(); - - WriteObject(result, false); - } - else - { - WriteVerbose($"Retrieving all Connectors within environment '{environmentName}'"); - - var connectors = GraphHelper.GetResultCollectionAsync(Connection, $"https://api.powerapps.com/providers/Microsoft.PowerApps/apis?api-version=2016-11-01&$filter=environment eq '{environmentName}' and isCustomApi eq 'True'", AccessToken).GetAwaiter().GetResult(); - WriteObject(connectors, true); - } - - } - } -} \ No newline at end of file