diff --git a/src/Beta/Users.User/Users.User/readme.md b/src/Beta/Users.User/Users.User/readme.md index f83779b1fa9..761faec1931 100644 --- a/src/Beta/Users.User/Users.User/readme.md +++ b/src/Beta/Users.User/Users.User/readme.md @@ -34,6 +34,6 @@ input-file: $(spec-doc-repo)/$(title).yml ### Versioning ``` yaml -module-version: 0.5.1 +module-version: 0.7.0 release-notes: See https://aka.ms/GraphPowerShell-Release. ``` diff --git a/src/readme.graph.md b/src/readme.graph.md index 9a5451e343e..f8893b802a4 100644 --- a/src/readme.graph.md +++ b/src/readme.graph.md @@ -81,7 +81,9 @@ directive: parameter-name: Top set: parameter-name: PageSize - alias: Top + alias: + - Top + - Limit - where: parameter-name: Select set: @@ -378,7 +380,7 @@ directive: } return $; } -# Temporarily disable paging. +# Add custom -All parameter to *_List cmdlets that support Odata next link. - from: source-file-csharp where: $ transform: > @@ -388,7 +390,15 @@ directive: } else { let odataNextLinkRegex = /(^\s*)(if\s*\(\s*result.OdataNextLink\s*!=\s*null\s*\))/gmi if($.match(odataNextLinkRegex)) { - $ = $.replace(odataNextLinkRegex, '$1result.OdataNextLink = null;\n$1if (result.OdataNextLink != null)$1'); + $ = $.replace(odataNextLinkRegex, '$1if (result.OdataNextLink != null && this.ShouldIteratePages(this.InvocationInformation.BoundParameters, result.Value.Length))\n$1'); + let psBaseClassImplementationRegex = /(\s*:\s*)(global::System.Management.Automation.PSCmdlet)/gmi + $ = $.replace(psBaseClassImplementationRegex, '$1Microsoft.Graph.PowerShell.Cmdlets.Custom.ListCmdlet'); + + let beginProcessingRegex = /(^\s*)(protected\s*override\s*void\s*BeginProcessing\(\)\s*{)/gmi + $ = $.replace(beginProcessingRegex, '$1$2\n$1$1if (this.InvocationInformation.BoundParameters.ContainsKey("PageSize")){ InitializePaging(ref this.__invocationInfo, ref this._pageSize); }\n$1'); + + let odataNextLinkCallRegex = /(^\s*)(await\s*this\.Client\.UsersUserListUser_Call\(requestMessage\,\s*onOk\,\s*onDefault\,\s*this\,\s*Pipeline\)\;)/gmi + $ = $.replace(odataNextLinkCallRegex, '$1requestMessage.RequestUri = GetOverflowItemsNextLinkUri(requestMessage.RequestUri);\n$1$2'); } return $; } diff --git a/tools/Custom/ListCmdlet.cs b/tools/Custom/ListCmdlet.cs new file mode 100644 index 00000000000..2fd7cdd448c --- /dev/null +++ b/tools/Custom/ListCmdlet.cs @@ -0,0 +1,118 @@ +// ------------------------------------------------------------------------------ +// 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.Cmdlets.Custom +{ + + public partial class ListCmdlet : global::System.Management.Automation.PSCmdlet + { + /// Backing field for property. + private global::System.Management.Automation.SwitchParameter _all; + + /// List All pages + [global::System.Management.Automation.Parameter(Mandatory = false, HelpMessage = "List all pages")] + [Microsoft.Graph.PowerShell.Runtime.Info( + Required = false, + ReadOnly = false, + Description = @"List all pages", + SerializedName = @"$all", + PossibleTypes = new[] { typeof(global::System.Management.Automation.SwitchParameter) })] + [global::Microsoft.Graph.PowerShell.Category(global::Microsoft.Graph.PowerShell.ParameterCategory.Runtime)] + public global::System.Management.Automation.SwitchParameter All { get => this._all; set => this._all = value; } + + /// + /// Default number of items per page. + /// + internal const int DefaultPageSize = 100; + + /// + /// Maximum number of items per page. + /// + internal const int MaxPageSize = 999; + + /// + /// Original page size/top/limit passed to Cmdlet via parameter. + /// + internal int originalPageSize = 0; + + /// + /// Total number of pages required to iterate page collections excluding overflow items. + /// + internal int requiredPages = 0; + + /// + /// A count of iterated pages thus far. + /// + internal int iteratedPages = 0; + + /// + /// Total number of overflow items, less than the maximum number of items in a page. + /// Modulus of original page size. + /// + internal int overflowItemsCount = 0; + + /// + /// Total number of fetched items. + /// + internal int totalFetchedItems = 0; + + /// + /// Initializes paging values. + /// + /// A reference to object. + /// A reference to page size parameter. + public void InitializePaging(ref global::System.Management.Automation.InvocationInfo invocationInfo, ref int PageSize) + { + if (PageSize > MaxPageSize) + { + invocationInfo.BoundParameters["All"] = true; + originalPageSize = PageSize; + requiredPages = PageSize / DefaultPageSize; + overflowItemsCount = PageSize % DefaultPageSize; + invocationInfo.BoundParameters["PageSize"] = DefaultPageSize; + PageSize = DefaultPageSize; + } + } + + /// + /// Determines whether the cmdlet should follow the OData next link url. + /// + /// The bound parameters of the cmdlet. + /// Current page items count. + /// True if it can iterate pages; False if it can't. + public bool ShouldIteratePages(global::System.Collections.Generic.Dictionary boundParameters, int itemsCount) + { + iteratedPages++; + totalFetchedItems += itemsCount; + if ((boundParameters.ContainsKey("All") && !boundParameters.ContainsKey("PageSize")) || + (boundParameters.ContainsKey("PageSize") && totalFetchedItems < originalPageSize)) + return true; + else + return false; + } + + /// + /// Gets an OData next link for the overflow items. + /// + /// The OData next link returned by the service. + /// An OData next link URI for the overflow items. + public global::System.Uri GetOverflowItemsNextLinkUri(global::System.Uri requestUri) + { + var nextLinkUri = new global::System.UriBuilder(requestUri); + if (requiredPages == iteratedPages && overflowItemsCount > 0) + { + if (nextLinkUri.Query.Contains("$top")) + { + global::System.Collections.Specialized.NameValueCollection queryString = global::System.Web.HttpUtility.ParseQueryString(nextLinkUri.Query); + queryString["$top"] = global::System.Uri.EscapeDataString(overflowItemsCount.ToString()); + nextLinkUri.Query = queryString.ToString(); + } + else + { + nextLinkUri.Query += $"$top=" + global::System.Uri.EscapeDataString(overflowItemsCount.ToString()); + } + } + return nextLinkUri.Uri; + } + } +} \ No newline at end of file