Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added `-Contributors` and `-Managers` parameters to `New-PnPTermGroup` and `Set-PnPTermGroup` cmdlets.
- Added `-Files` parameter for `Send-PnPMail` cmdlet to allow files to be downloaded from SharePoint and then sent as attachments.
- Added `-Force` parameter to `Set-PnPPropertyBagValue` cmdlet to toggle NoScript status of the site.
- Added `-Batch` parameter to `Invoke-PnPGraphMethod` cmdlet to allow adding request in a batch.

### Changed

Expand Down
40 changes: 40 additions & 0 deletions documentation/Invoke-PnPGraphMethod.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ Invoke-PnPGraphMethod -Url <String>
[-Verbose]
```

### Batch
```powershell
Invoke-PnPGraphMethod -Url <String>
[-AdditionalHeaders GraphAdditionalHeadersPipeBind]
[[-Method] <HttpRequestMethod>]
[-Content <Object>]
[-ContentType <String>]
[-ConsistencyLevelEventual]
[-Connection <PnPConnection>]
[-Batch <PnPBatch>]
[-Verbose]
```

## DESCRIPTION
Invokes a REST request towards the Microsoft Graph API. It will take care of potential throttling retries that are needed to retrieve the data.

Expand Down Expand Up @@ -120,6 +133,18 @@ Invoke-PnPGraphMethod -Url "https://graph.microsoft.com/v1.0/planner/tasks/23fas

This example retrieves a Planner task to find the etag value which is required to update the task. In order to update the task through call to the Microsoft Graph API we need to include an If-Match header with the value of the etag. It then creates the content to update, in this case the title of the task, and calls the PATCH method on the Graph end-point to update the specific task.

### EXAMPLE 9
```powershell
$batch = New-PnPBatch -RetainRequests
Invoke-PnPSPRestMethod -Method Get -Url "https://graph.microsoft.com/v1.0/users" -Batch $batch
Invoke-PnPSPRestMethod -Method Get -Url "https://graph.microsoft.com/v1.0/groups" -Batch $batch
$response = Invoke-PnPBatch $batch -Details
$response
```

This example executes a GET request to get all users and a groups in a single batch request.
It is necessary to create and invoke batch requests in the manner specified here if you want to process something later on with the response object.

## PARAMETERS

### -AdditionalHeaders
Expand Down Expand Up @@ -290,6 +315,21 @@ Accept pipeline input: True (ByValue)
Accept wildcard characters: False
```

### -Batch

The batch to add this request to.

```yaml
Type: PnPBatch
Parameter Sets: Batched

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
15 changes: 15 additions & 0 deletions documentation/Invoke-PnPSPRestMethod.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ Position: Named
Accept pipeline input: False
```

### -Batch

The batch to add this request to.

```yaml
Type: PnPBatch
Parameter Sets: Batched

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
Expand Down
8 changes: 4 additions & 4 deletions src/Commands/Base/InvokeSPRestMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ public class InvokeSPRestMethod : PnPSharePointCmdlet

[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Parsed)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Raw)]
[Parameter(Mandatory = false, Position = 0, ParameterSetName = PARAMETERSET_Batch)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public object Content;

[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Parsed)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Raw)]
[Parameter(Mandatory = false, Position = 0, ParameterSetName = PARAMETERSET_Batch)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public string ContentType = "application/json";

[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Parsed)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Raw)]
[Parameter(Mandatory = false, Position = 0, ParameterSetName = PARAMETERSET_Batch)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public string Accept = "application/json;odata=nometadata";

[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Raw)]
Expand All @@ -58,7 +58,7 @@ public class InvokeSPRestMethod : PnPSharePointCmdlet
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Raw)]
public string ResponseHeadersVariable;

[Parameter(Mandatory = false, Position = 0, ParameterSetName = PARAMETERSET_Batch)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public PnPBatch Batch;

protected override void ExecuteCmdlet()
Expand Down
75 changes: 65 additions & 10 deletions src/Commands/Graph/InvokeGraphMethod.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using PnP.Framework.Utilities;
using PnP.Core.Model;
using PnP.Core.Services;
using PnP.Framework.Utilities;
using PnP.PowerShell.Commands.Base.PipeBinds;
using PnP.PowerShell.Commands.Enums;
using PnP.PowerShell.Commands.Model;
using PnP.PowerShell.Commands.Utilities.REST;
using System;
using System.Management.Automation;
using System.Text.Json;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.IO;
using PnP.PowerShell.Commands.Base.PipeBinds;

namespace PnP.PowerShell.Commands.Base
{
Expand All @@ -19,16 +22,19 @@ public class InvokeGraphMethod : PnPGraphCmdlet
private const string ParameterSet_TOSTREAM = "Out to stream";
private const string ParameterSet_TOFILE = "Out to file";
private const string ParameterSet_TOCONSOLE = "Out to console";
public const string PARAMETERSET_Batch = "Batch";

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public HttpRequestMethod Method = HttpRequestMethod.Get;

private string _url;

[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_TOSTREAM)]
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = PARAMETERSET_Batch)]
public string Url
{
get { return _url; }
Expand All @@ -53,25 +59,29 @@ public string Url
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOSTREAM)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public object Content;

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOSTREAM)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public string ContentType = "application/json";

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOSTREAM)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public GraphAdditionalHeadersPipeBind AdditionalHeaders = new(new Dictionary<string, string>());

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOSTREAM)]
[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public SwitchParameter ConsistencyLevelEventual;

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
public SwitchParameter Raw;
public SwitchParameter Raw;

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
public SwitchParameter All;
Expand All @@ -82,11 +92,21 @@ public string Url
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_TOSTREAM)]
public SwitchParameter OutStream;

[Parameter(Mandatory = false, ParameterSetName = PARAMETERSET_Batch)]
public PnPBatch Batch;

protected override void ExecuteCmdlet()
{
try
{
SendRequest();
if (ParameterSpecified(nameof(Batch)))
{
CallBatchRequest(new HttpMethod(Method.ToString().ToUpper()), Url);
}
else
{
SendRequest();
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -123,7 +143,7 @@ private void SendRequest()
switch (Method)
{
case HttpRequestMethod.Get:
if(ParameterSetName == ParameterSet_TOCONSOLE)
if (ParameterSetName == ParameterSet_TOCONSOLE)
{
GetRequestWithPaging();
}
Expand Down Expand Up @@ -235,7 +255,7 @@ private void GetRequestWithPaging()
WriteObject(rootObj);
}
}

private void GetRequestWithoutPaging()
{
WriteVerbose($"Sending HTTP GET to {Url}");
Expand Down Expand Up @@ -298,7 +318,7 @@ private void HandleResponse(HttpResponseMessage response)

case ParameterSet_TOSTREAM:
var responseStream = response.Content.ReadAsStream();

WriteVerbose($"Writing {responseStream.Length} bytes response to outputstream");

var memoryStream = new MemoryStream();
Expand All @@ -315,5 +335,40 @@ private void HandleResponse(HttpResponseMessage response)
throw new Exception($"Parameter set {ParameterSetName} not supported");
}
}

private void CallBatchRequest(HttpMethod method, string requestUrl)
{
var web = Connection.PnPContext.Web;
string contentString = null;
if (ParameterSpecified(nameof(Content)))
{
contentString = Content is string ? Content.ToString() :
JsonSerializer.Serialize(Content, new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true });

}

Dictionary<string, string> extraHeaders = AdditionalHeaders?.GetHeaders(ConsistencyLevelEventual.IsPresent);
extraHeaders.Add("Content-Type", ContentType);

ApiRequestType apiRequestType = ApiRequestType.Graph;
if (requestUrl.IndexOf("/beta/", StringComparison.InvariantCultureIgnoreCase) > -1)
{
apiRequestType = ApiRequestType.GraphBeta;
}

if (requestUrl.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
{
if (requestUrl.IndexOf("/v1.0/", StringComparison.InvariantCultureIgnoreCase) > -1)
{
requestUrl = requestUrl.Replace($"https://{Connection.GraphEndPoint}/v1.0/", "", StringComparison.InvariantCultureIgnoreCase);
}
else if (requestUrl.IndexOf("/beta/", StringComparison.InvariantCultureIgnoreCase) > -1)
{
requestUrl = requestUrl.Replace($"https://{Connection.GraphEndPoint}/beta/", "", StringComparison.InvariantCultureIgnoreCase);
}
}

web.WithHeaders(extraHeaders).ExecuteRequestBatch(Batch.Batch, new ApiRequest(method, apiRequestType, requestUrl, contentString));
}
}
}
Loading