Skip to content

Commit eb6d17b

Browse files
authored
Merge pull request #2971 from KoenZomers/InvokePnPGraphMethodToFile
Adding option to write Graph output from `Invoke-PnPGraphMethod` to file
2 parents f8d82d4 + e088da1 commit eb6d17b

File tree

3 files changed

+112
-24
lines changed

3 files changed

+112
-24
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
1010

1111
### Added
1212

13+
- Added `-OutFile` to `Invoke-PnPGraphMethod` which allows for the response to be written to a file [#2971](https://github.com/pnp/powershell/pull/2971)
14+
1315
### Contributors
1416

1517
- [dhiabedoui]
18+
- Koen Zomers [koenzomers]
1619

1720
## [2.1.1]
1821

documentation/Invoke-PnPGraphMethod.md

+40-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Invokes a REST request towards the Microsoft Graph API
1414

1515
## SYNTAX
1616

17+
### Out to console (Default)
1718
```powershell
1819
Invoke-PnPGraphMethod -Url <String>
1920
[-AdditionalHeaders <System.Collections.Generic.IDictionary`2[System.String,System.String]>]
@@ -24,7 +25,20 @@ Invoke-PnPGraphMethod -Url <String>
2425
[-Raw]
2526
[-All]
2627
[-Connection <PnPConnection>]
27-
[<CommonParameters>]
28+
[-Verbose]
29+
```
30+
31+
### Out to file
32+
```powershell
33+
Invoke-PnPGraphMethod -Url <String>
34+
[-AdditionalHeaders <System.Collections.Generic.IDictionary`2[System.String,System.String]>]
35+
[[-Method] <HttpRequestMethod>]
36+
[-Content <Object>]
37+
[-ContentType <String>]
38+
[-ConsistencyLevelEventual]
39+
[-Connection <PnPConnection>]
40+
[-OutFile <String>]
41+
[-Verbose]
2842
```
2943

3044
## DESCRIPTION
@@ -68,6 +82,13 @@ Invoke-PnPGraphMethod "https://graph.microsoft.com/v1.0/users"
6882

6983
Performs a GET request to retrieve users from the Microsoft Graph API using the full URL.
7084

85+
### Example 6
86+
```powershell
87+
Invoke-PnPGraphMethod "https://graph.microsoft.com/v1.0/users/user@contoso.com/photo/`$value" -OutFile c:\temp\photo.jpg
88+
```
89+
90+
Downloads the user profile photo of the specified user to the specified file.
91+
7192
## PARAMETERS
7293

7394
### -AdditionalHeaders
@@ -90,7 +111,7 @@ Retrieve all pages of results. This will loop through all @odata.nextLink. This
90111
91112
```yaml
92113
Type: SwitchParameter
93-
Parameter Sets: (All)
114+
Parameter Sets: Out to console
94115
Aliases:
95116

96117
Required: False
@@ -178,12 +199,27 @@ Accept pipeline input: False
178199
Accept wildcard characters: False
179200
```
180201
202+
### -OutFile
203+
The full path including filename to write the output to, i.e. c:\temp\myfile.txt. Existing files will be overwritten.
204+
205+
```yaml
206+
Type: String
207+
Parameter Sets: Out to file
208+
Aliases:
209+
210+
Required: True
211+
Position: Named
212+
Default value: None
213+
Accept pipeline input: False
214+
Accept wildcard characters: False
215+
```
216+
181217
### -Raw
182218
If specified the returned data will not be converted to an object but returned as a JSON string.
183219
184220
```yaml
185221
Type: SwitchParameter
186-
Parameter Sets: (All)
222+
Parameter Sets: Out to console
187223
Aliases:
188224

189225
Required: False
@@ -210,4 +246,4 @@ Accept wildcard characters: False
210246
211247
## RELATED LINKS
212248
213-
[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
249+
[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)

src/Commands/Graph/InvokeGraphMethod.cs

+69-20
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@
1111

1212
namespace PnP.PowerShell.Commands.Base
1313
{
14-
[Cmdlet(VerbsLifecycle.Invoke, "PnPGraphMethod")]
14+
[Cmdlet(VerbsLifecycle.Invoke, "PnPGraphMethod", DefaultParameterSetName = ParameterSet_TOCONSOLE)]
1515
public class InvokeGraphMethod : PnPGraphCmdlet
1616
{
17-
[Parameter(Mandatory = false)]
17+
private const string ParameterSet_TOFILE = "Out to file";
18+
private const string ParameterSet_TOCONSOLE = "Out to console";
19+
20+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
21+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
1822
public HttpRequestMethod Method = HttpRequestMethod.Get;
1923

2024
private string _url;
2125

22-
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true)]
26+
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_TOFILE)]
27+
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ParameterSetName = ParameterSet_TOCONSOLE)]
2328
public string Url
2429
{
2530
get { return _url; }
@@ -41,15 +46,18 @@ public string Url
4146
}
4247
}
4348

44-
[Parameter(Mandatory = false)]
49+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
50+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
4551
public object Content;
4652

47-
[Parameter(Mandatory = false)]
53+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
54+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
4855
public string ContentType = "application/json";
4956

5057
IDictionary<string, string> additionalHeaders = null;
5158

52-
[Parameter(Mandatory = false)]
59+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
60+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
5361
public IDictionary<string, string> AdditionalHeaders
5462
{
5563
get
@@ -71,15 +79,19 @@ public IDictionary<string, string> AdditionalHeaders
7179
}
7280
}
7381

74-
[Parameter(Mandatory = false)]
82+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOFILE)]
83+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
7584
public SwitchParameter ConsistencyLevelEventual;
7685

77-
[Parameter(Mandatory = false)]
78-
public SwitchParameter Raw;
86+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
87+
public SwitchParameter Raw;
7988

80-
[Parameter(Mandatory = false)]
89+
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_TOCONSOLE)]
8190
public SwitchParameter All;
8291

92+
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_TOFILE)]
93+
public string OutFile;
94+
8395
protected override void ExecuteCmdlet()
8496
{
8597
try
@@ -121,7 +133,14 @@ private void SendRequest()
121133
switch (Method)
122134
{
123135
case HttpRequestMethod.Get:
124-
GetRequest();
136+
if(string.IsNullOrWhiteSpace(OutFile))
137+
{
138+
GetRequestWithPaging();
139+
}
140+
else
141+
{
142+
GetRequestWithoutPaging();
143+
}
125144
return;
126145
case HttpRequestMethod.Post:
127146
PostRequest();
@@ -178,7 +197,7 @@ private void WriteGraphResult(string result)
178197
}
179198
}
180199

181-
private void GetRequest()
200+
private void GetRequestWithPaging()
182201
{
183202
var result = GraphHelper.GetAsync(Connection, Url, AccessToken, AdditionalHeaders).GetAwaiter().GetResult();
184203
if (Raw.IsPresent)
@@ -226,33 +245,63 @@ private void GetRequest()
226245
WriteObject(rootObj);
227246
}
228247
}
248+
249+
private void GetRequestWithoutPaging()
250+
{
251+
WriteVerbose($"Sending HTTP GET to {Url}");
252+
using var response = GraphHelper.GetResponseAsync(Connection, Url, AccessToken).GetAwaiter().GetResult();
253+
HandleResponse(response);
254+
}
229255

230256
private void PostRequest()
231257
{
258+
WriteVerbose($"Sending HTTP POST to {Url}");
232259
var response = GraphHelper.PostAsync(Connection, Url, AccessToken, GetHttpContent(), AdditionalHeaders).GetAwaiter().GetResult();
233-
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
234-
WriteGraphResult(result);
260+
HandleResponse(response);
235261
}
236262

237263
private void PutRequest()
238264
{
265+
WriteVerbose($"Sending HTTP PUT to {Url}");
239266
var response = GraphHelper.PutAsync(Connection, Url, AccessToken, GetHttpContent(), AdditionalHeaders).GetAwaiter().GetResult();
240-
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
241-
WriteGraphResult(result);
267+
HandleResponse(response);
242268
}
243269

244270
private void PatchRequest()
245271
{
272+
WriteVerbose($"Sending HTTP PATCH to {Url}");
246273
var response = GraphHelper.PatchAsync(Connection, AccessToken, GetHttpContent(), Url, AdditionalHeaders).GetAwaiter().GetResult();
247-
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
248-
WriteGraphResult(result);
274+
HandleResponse(response);
249275
}
250276

251277
private void DeleteRequest()
252278
{
279+
WriteVerbose($"Sending HTTP DELETE to {Url}");
253280
var response = GraphHelper.DeleteAsync(Connection, Url, AccessToken, AdditionalHeaders).GetAwaiter().GetResult();
254-
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
255-
WriteGraphResult(result);
281+
HandleResponse(response);
256282
}
283+
284+
private void HandleResponse(HttpResponseMessage response)
285+
{
286+
if(ParameterSpecified(nameof(OutFile)))
287+
{
288+
var responseStream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult();
289+
290+
WriteVerbose($"Writing {responseStream.Length} bytes response to {OutFile}");
291+
292+
using var fileStream = new System.IO.FileStream(OutFile, System.IO.FileMode.Create, System.IO.FileAccess.Write);
293+
responseStream.CopyTo(fileStream);
294+
fileStream.Close();
295+
return;
296+
}
297+
else
298+
{
299+
var result = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
300+
301+
WriteVerbose($"Returning {result.Length} characters response");
302+
303+
WriteGraphResult(result);
304+
}
305+
}
257306
}
258307
}

0 commit comments

Comments
 (0)