Skip to content

Commit 2a6e2c0

Browse files
authored
Merge pull request #9 from OfficeDev/soocho/OAuthSupport
Update examples to use OAuth.
2 parents 992a94e + 2557353 commit 2a6e2c0

9 files changed

+239
-137
lines changed

README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
---
2-
page_type: sample
3-
products:
4-
- office-project
5-
- office-365
6-
languages:
7-
- powershell
8-
extensions:
9-
contentType: samples
10-
platforms:
11-
- REST API
12-
createdDate: 11/23/2015 8:07:26 PM
13-
---
1+
---
2+
page_type: sample
3+
products:
4+
- office-project
5+
- office-365
6+
languages:
7+
- powershell
8+
extensions:
9+
contentType: samples
10+
platforms:
11+
- REST API
12+
createdDate: 11/23/2015 8:07:26 PM
13+
---
1414
# Project REST Basic Operations
1515

1616
The Project REST Basic Operations demonstrates how to create and update a project using REST API
1717

1818
###Prerequisites
1919
To use this Project Online REST code sample, you need the following:
2020
* An Office 365 tenant with a Project license
21-
* Project CSOM client library. It is available as a Nuget Package from [here](https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM/)
2221
* PowerShell v4.0
22+
* Latest ADAL.NET library. It is available as a Nuget Package from [here](https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/)
23+
* For the files downloaded, please run "Unblock-File *" to unblock accessing the file.
2324

2425
###Modules
2526
* [CreateProject](/createproject.ps1)

ReST.ps1

Lines changed: 98 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,70 @@
33
See LICENSE in the project root for license information.
44
#>
55

6+
$ErrorActionPreference = "Stop" # http://technet.microsoft.com/en-us/library/dd347731.aspx
7+
Set-StrictMode -Version "Latest" # http://technet.microsoft.com/en-us/library/dd347614.aspx
8+
69
# PS helper methods to call ReST API methods targeting Project Online tenants
7-
$global:fedAuthTicket = ''
10+
$global:accessHeader = ''
811
$global:digestValue = ''
912

13+
[Reflection.Assembly]::LoadFrom("$($PSScriptRoot)\Microsoft.IdentityModel.Clients.ActiveDirectory.dll") | Out-Null
14+
15+
function Get-AADAuthToken([Uri] $Uri)
16+
{
17+
# NOTE: Create an azure app and update $clientId and $redirectUri below
18+
$clientId = ""
19+
$redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
20+
21+
$authority = "https://login.microsoftonline.com/common"
22+
$resource = $Uri.GetLeftPart([System.UriPartial]::Authority);
23+
24+
$promptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always
25+
$platformParam = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList $promptBehavior
26+
$authenticationContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority, $False
27+
$authenticationResult = $authenticationContext.AcquireTokenAsync($resource, $clientId, $redirectUri, $platformParam).Result
28+
29+
return $authenticationResult
30+
}
31+
1032
function Set-SPOAuthenticationTicket([string] $siteUrl)
1133
{
12-
$username = "[email protected]"
13-
Write-Host 'Enter password for user' $username 'on site' $siteUrl
14-
$password = Read-Host -AsSecureString
34+
$siteUri = New-Object Uri -ArgumentList $siteUrl
35+
36+
$authResult = Get-AADAuthToken -Uri $siteUri
37+
if ($authResult -ne $null)
38+
{
39+
$global:accessHeader = $authResult.AccessTokenType + " " + $authResult.AccessToken
40+
}
1541

16-
# load the SP client runtime code
17-
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
18-
$onlineCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password)
19-
if ($onlineCredentials -ne $null)
20-
{
21-
$global:fedAuthTicket = $onlineCredentials.GetAuthenticationCookie($SiteUrl, $true).TrimStart('SPOIDCRL=')
22-
}
23-
24-
if ([String]::IsNullOrEmpty($global:fedAuthTicket))
25-
{
26-
throw 'Could not obtain authentication ticket based on provided credentials for specified site'
27-
}
42+
if ([String]::IsNullOrEmpty($global:accessHeader))
43+
{
44+
throw 'Could not obtain authentication ticket based on provided credentials for specified site'
45+
}
2846
}
2947

3048
function Build-ReSTRequest([string] $siteUrl, [string]$endpoint, [string]$method, [string]$body = $null)
3149
{
32-
$url = ([string]$siteUrl).TrimEnd("/") + "/_api/" + $endpoint
33-
$req = [System.Net.WebRequest]::Create($url)
34-
$req.Method = $method
35-
36-
[bool]$isReadOnly = (('GET','HEAD') -contains $req.Method)
37-
[bool]$isDigestRequest = $endpoint -contains 'contextinfo'
38-
39-
if ([String]::IsNullOrEmpty($body))
40-
{
41-
$req.ContentLength = 0;
42-
}
43-
else
44-
{
45-
$req.ContentLength = $body.Length
46-
$req.ContentType = "application/json"
47-
}
48-
49-
$domain = (New-Object System.Uri($url)).Authority
50-
$cookies = New-Object System.Net.CookieContainer
51-
$fedCookie = New-Object System.Net.Cookie 'SPOIDCRL', $global:fedAuthTicket, "", $domain
52-
$cookies.Add($fedCookie)
50+
$url = ([string]$siteUrl).TrimEnd("/") + "/_api/" + $endpoint
51+
$req = [System.Net.WebRequest]::Create($url)
52+
$req.Timeout = 120000
53+
$req.Method = $method
5354

54-
$req.CookieContainer = $cookies
55+
[bool]$isReadOnly = (('GET','HEAD') -contains $req.Method)
56+
[bool]$isDigestRequest = $endpoint -contains 'contextinfo'
57+
58+
if ([String]::IsNullOrEmpty($body))
59+
{
60+
$req.ContentLength = 0;
61+
}
62+
else
63+
{
64+
$req.ContentLength = $body.Length
65+
$req.ContentType = "application/json"
66+
}
67+
68+
# set Authorization header
69+
$req.Headers.Add("Authorization", $global:accessHeader)
5570

5671
if (-not $isDigestRequest)
5772
{
@@ -60,57 +75,57 @@ function Build-ReSTRequest([string] $siteUrl, [string]$endpoint, [string]$method
6075
$req.Headers.Add("X-RequestDigest", $global:digestValue)
6176
}
6277
}
63-
64-
if (-not [String]::IsNullOrEmpty($body))
65-
{
66-
$writer = New-Object System.IO.StreamWriter $req.GetRequestStream()
67-
$writer.Write($body)
68-
$writer.Close()
78+
79+
if (-not [String]::IsNullOrEmpty($body))
80+
{
81+
$writer = New-Object System.IO.StreamWriter $req.GetRequestStream()
82+
$writer.Write($body)
83+
$writer.Close()
6984
$writer.Dispose()
70-
}
71-
72-
return $req
85+
}
86+
87+
return $req
7388
}
7489

7590
function Set-DigestValue([string]$siteUrl)
7691
{
77-
$request = Build-ReSTRequest $siteUrl 'contextinfo' 'POST' $null
78-
if ($request -eq $null)
79-
{
80-
throw 'Could not obtain a request digest value based on provided credentials for specified site'
81-
}
82-
83-
try
84-
{
85-
$resp = $request.GetResponse()
86-
$reader = [System.Xml.XmlReader]::Create($resp.GetResponseStream())
87-
if ($reader.ReadToDescendant("d:FormDigestValue"))
88-
{
89-
$global:digestValue = $reader.ReadElementContentAsString()
90-
}
91-
else
92-
{
93-
throw 'Could not obtain a request digest value based on provided credentials for specified site'
94-
}
95-
}
96-
finally
97-
{
98-
if ($reader -ne $null)
99-
{
100-
$reader.Close()
101-
$reader.Dispose()
102-
}
103-
if ($resp -ne $null)
104-
{
105-
$resp.Close()
106-
$resp.Dispose()
107-
}
108-
}
92+
$request = Build-ReSTRequest $siteUrl 'contextinfo' 'POST' $null
93+
if ($request -eq $null)
94+
{
95+
throw 'Could not obtain a request digest value based on provided credentials for specified site'
96+
}
97+
98+
try
99+
{
100+
$resp = $request.GetResponse()
101+
$reader = [System.Xml.XmlReader]::Create($resp.GetResponseStream())
102+
if ($reader.ReadToDescendant("d:FormDigestValue"))
103+
{
104+
$global:digestValue = $reader.ReadElementContentAsString()
105+
}
106+
else
107+
{
108+
throw 'Could not obtain a request digest value based on provided credentials for specified site'
109+
}
110+
}
111+
finally
112+
{
113+
if ($reader -ne $null)
114+
{
115+
$reader.Close()
116+
$reader.Dispose()
117+
}
118+
if ($resp -ne $null)
119+
{
120+
$resp.Close()
121+
$resp.Dispose()
122+
}
123+
}
109124
}
110125

111126
function Post-ReSTRequest([string]$siteUrl, [string]$endpoint, [string]$body = $null)
112127
{
113-
$request = Build-ReSTRequest $siteUrl $endpoint 'POST' $body
128+
$request = Build-ReSTRequest $siteUrl $endpoint 'POST' $body
114129
$resp = $request.GetResponse()
115130
if ($resp -ne $null)
116131
{
@@ -122,7 +137,7 @@ function Post-ReSTRequest([string]$siteUrl, [string]$endpoint, [string]$body = $
122137

123138
function Patch-ReSTRequest([string]$siteUrl, [string]$endpoint, [string]$body)
124139
{
125-
$request = Build-ReSTRequest $siteUrl $endpoint 'PATCH' $body
140+
$request = Build-ReSTRequest $siteUrl $endpoint 'PATCH' $body
126141
$resp = $request.GetResponse()
127142
if ($resp -ne $null)
128143
{
@@ -134,12 +149,12 @@ function Patch-ReSTRequest([string]$siteUrl, [string]$endpoint, [string]$body)
134149

135150
function Get-ReSTRequest([string]$siteUrl, [string]$endpoint)
136151
{
137-
$request = Build-ReSTRequest $siteUrl $endpoint 'GET'
152+
$request = Build-ReSTRequest $siteUrl $endpoint 'GET'
138153
$resp = $request.GetResponse()
139154
if ($resp -ne $null)
140155
{
141156
$reader = New-Object System.IO.StreamReader $resp.GetResponseStream()
142157
$reader.ReadToEnd()
143-
$reader.Dispose()
158+
$reader.Dispose()
144159
}
145160
}

createproject.ps1

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ Set-DigestValue $siteUrl
2020
# Project parameters as JSON payload
2121
$projectid = [Guid]::NewGuid()
2222
$body = "{
23-
'parameters': {
24-
'Id': '$projectid',
25-
'Name': 'Project_$projectid',
26-
'Description': 'Created from PowerShell using REST API'
27-
}
23+
'parameters': {
24+
'Id': '$projectid',
25+
'Name': 'Project_$projectid',
26+
'Description': 'Created from PowerShell using REST API'
27+
}
2828
}"
2929

3030
# ReST request to create a project
@@ -49,13 +49,13 @@ Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/checkOut" $null
4949
# Task parameters as JSON payload
5050
$taskid = [Guid]::NewGuid()
5151
$body = "{
52-
'parameters': {
53-
'Id': '$taskid',
54-
'Name': 'Task_$taskid',
55-
'Notes': 'Created from PowerShell using REST API',
56-
'Start': '2016-01-04T08:00:00',
57-
'Duration': '5d'
58-
}
52+
'parameters': {
53+
'Id': '$taskid',
54+
'Name': 'Task_$taskid',
55+
'Notes': 'Created from PowerShell using REST API',
56+
'Start': '2016-01-04T08:00:00',
57+
'Duration': '5d'
58+
}
5959
}"
6060

6161
# ReST request to create a task
@@ -64,10 +64,10 @@ Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add"
6464
# Resource parameters as JSON payload
6565
$resourceid = [Guid]::NewGuid()
6666
$body = "{
67-
'parameters': {
68-
'Id': '$resourceid',
69-
'Name': 'Resource_$resourceid'
70-
}
67+
'parameters': {
68+
'Id': '$resourceid',
69+
'Name': 'Resource_$resourceid'
70+
}
7171
}"
7272

7373
# ReST request to create a local resource
@@ -76,10 +76,10 @@ Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/ProjectRes
7676
# Enterprise resource parameters as JSON payload
7777
$enterprise_resourceid = [Guid]::NewGuid()
7878
$body = "{
79-
'parameters': {
80-
'Id': '$enterprise_resourceid',
81-
'Name': 'EnterpriseResource_$enterprise_resourceid'
82-
}
79+
'parameters': {
80+
'Id': '$enterprise_resourceid',
81+
'Name': 'EnterpriseResource_$enterprise_resourceid'
82+
}
8383
}"
8484

8585
# ReST request to create an enterprise resource
@@ -90,23 +90,23 @@ Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/ProjectRes
9090

9191
# Assignment parameters as JSON payload
9292
$body = "{
93-
'parameters': {
94-
'ResourceId': '$resourceid',
95-
'TaskId': '$taskid',
96-
'Notes': 'Created from PowerShell using REST API'
97-
}
93+
'parameters': {
94+
'ResourceId': '$resourceid',
95+
'TaskId': '$taskid',
96+
'Notes': 'Created from PowerShell using REST API'
97+
}
9898
}"
9999

100100
# ReST request to create an assignment for the local resource
101101
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Assignments/Add" $body
102102

103103
# Assignment parameters as JSON payload
104104
$body = "{
105-
'parameters': {
106-
'ResourceId': '$enterprise_resourceid',
107-
'TaskId': '$taskid',
108-
'Notes': 'Created from PowerShell using REST API'
109-
}
105+
'parameters': {
106+
'ResourceId': '$enterprise_resourceid',
107+
'TaskId': '$taskid',
108+
'Notes': 'Created from PowerShell using REST API'
109+
}
110110
}"
111111

112112
# ReST request to create an assignment for the enterprise resource

getprojectscsom.ps1

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<#
2+
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
3+
See LICENSE in the project root for license information.
4+
#>
5+
6+
7+
# Get list of projects using CSOM ReST API
8+
param
9+
(
10+
# SharepointOnline project site collection URL
11+
$SiteUrl = $(throw "SiteUrl parameter is required")
12+
)
13+
# Load ReST helper methods
14+
. .\ReST.ps1
15+
16+
# Set up the request authentication
17+
Set-SPOAuthenticationTicket $siteUrl
18+
Set-DigestValue $siteUrl
19+
20+
# Get list of projects using CSOM ReST API
21+
Get-ReSTRequest $SiteUrl "ProjectServer/Projects"

0 commit comments

Comments
 (0)