Skip to content

Commit f7de00c

Browse files
Merge pull request #16 from FriedrichWeinmann/development
1.3.12
2 parents 35c549e + 5f0adf9 commit f7de00c

18 files changed

+504
-19
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
TestResults
1+
TestResults
2+
publish

MiniGraph/MiniGraph.psd1

+8-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
RootModule = 'MiniGraph.psm1'
55

66
# Version number of this module.
7-
ModuleVersion = '1.2.7'
7+
ModuleVersion = '1.3.12'
88

99
# Supported PSEditions
1010
# CompatiblePSEditions = @()
@@ -63,13 +63,15 @@ Description = 'Minimal query infrastructure for interacting with MS Graph'
6363
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
6464
FunctionsToExport = @(
6565
'Connect-GraphAzure'
66-
'Connect-GraphCertificate'
67-
'Connect-GraphClientSecret'
68-
'Connect-GraphCredential'
66+
'Connect-GraphBrowser'
67+
'Connect-GraphCertificate'
68+
'Connect-GraphClientSecret'
69+
'Connect-GraphCredential'
6970
'Connect-GraphDeviceCode'
7071
'Connect-GraphToken'
71-
'Invoke-GraphRequest'
72-
'Set-GraphEndpoint'
72+
'Invoke-GraphRequest'
73+
'Invoke-GraphRequestBatch'
74+
'Set-GraphEndpoint'
7375
)
7476

7577
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.

MiniGraph/functions/Connect-GraphAzure.ps1

+10-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
Whether to risk showing a dialog during authentication.
1616
If set to never, it will fail if not possible to do silent authentication.
1717
Defaults to: Auto
18+
19+
.PARAMETER NoReconnect
20+
Disables automatic reconnection.
21+
By default, MiniGraph will automatically try to reaquire a new token before the old one expires.
1822
1923
.EXAMPLE
2024
PS C:\> Connect-GraphAzure
@@ -28,7 +32,10 @@
2832

2933
[ValidateSet('Auto', 'Always', 'Never')]
3034
[string]
31-
$ShowDialog = 'Auto'
35+
$ShowDialog = 'Auto',
36+
37+
[switch]
38+
$NoReconnect
3239
)
3340

3441
try { $azContext = Get-AzContext -ErrorAction Stop }
@@ -49,4 +56,6 @@
4956
catch { $PSCmdlet.ThrowTerminatingError($_) }
5057

5158
$script:token = $result.AccessToken
59+
60+
Set-ReconnectInfo -BoundParameters $PSBoundParameters -NoReconnect:$NoReconnect
5261
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
function Connect-GraphBrowser {
2+
<#
3+
.SYNOPSIS
4+
Interactive logon using the Authorization flow and browser. Supports SSO.
5+
6+
.DESCRIPTION
7+
Interactive logon using the Authorization flow and browser. Supports SSO.
8+
9+
This flow requires an App Registration configured for the platform "Mobile and desktop applications".
10+
Its redirect Uri must be "http://localhost"
11+
12+
On successful authentication
13+
14+
.PARAMETER ClientID
15+
The ID of the registered app used with this authentication request.
16+
17+
.PARAMETER TenantID
18+
The ID of the tenant connected to with this authentication request.
19+
20+
.PARAMETER SelectAccount
21+
Forces account selection on logon.
22+
As this flow supports single-sign-on, it will otherwise not prompt for anything if already signed in.
23+
This could be a problem if you want to connect using another (e.g. an admin) account.
24+
25+
.PARAMETER Scopes
26+
Generally doesn't need to be changed from the default 'https://graph.microsoft.com/.default'
27+
28+
.PARAMETER LocalPort
29+
The local port that should be redirected to.
30+
In order to process the authentication response, we need to listen to a local web request on some port.
31+
Usually needs not be redirected.
32+
Defaults to: 8080
33+
34+
.PARAMETER Resource
35+
The resource the token grants access to.
36+
Generally doesn't need to be changed from the default 'https://graph.microsoft.com/'
37+
Only needed when connecting to another service.
38+
39+
.PARAMETER Browser
40+
The path to the browser to use for the authentication flow.
41+
Provide the full path to the executable.
42+
The browser must accept the url to open as its only parameter.
43+
Defaults to Edge.
44+
45+
.PARAMETER NoReconnect
46+
Disables automatic reconnection.
47+
By default, MiniGraph will automatically try to reaquire a new token before the old one expires.
48+
49+
.EXAMPLE
50+
PS C:\> Connect-GraphBrowser -ClientID '<ClientID>' -TenantID '<TenantID>'
51+
52+
Connects to the specified tenant using the specified client, prompting the user to authorize via Browser.
53+
#>
54+
[CmdletBinding()]
55+
param (
56+
[Parameter(Mandatory = $true)]
57+
[string]
58+
$TenantID,
59+
60+
[Parameter(Mandatory = $true)]
61+
[string]
62+
$ClientID,
63+
64+
[switch]
65+
$SelectAccount,
66+
67+
[string[]]
68+
$Scopes = 'https://graph.microsoft.com/.default',
69+
70+
[int]
71+
$LocalPort = 8080,
72+
73+
[Uri]
74+
$Resource = 'https://graph.microsoft.com/',
75+
76+
[string]
77+
$Browser = $script:browserPath,
78+
79+
[switch]
80+
$NoReconnect
81+
)
82+
process {
83+
Add-Type -AssemblyName System.Web
84+
85+
$redirectUri = "http://localhost:$LocalPort"
86+
$actualScopes = foreach ($scope in $Scopes) {
87+
if ($scope -like 'https://*/*') { $scope }
88+
else { "{0}://{1}/{2}" -f $Resource.Scheme, $Resource.Host, $scope }
89+
}
90+
91+
if (-not $NoReconnect) {
92+
$actualScopes = @($actualScopes) + 'offline_access'
93+
}
94+
95+
$uri = "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/authorize?"
96+
$state = Get-Random
97+
$parameters = @{
98+
client_id = $ClientID
99+
response_type = 'code'
100+
redirect_uri = $redirectUri
101+
response_mode = 'query'
102+
scope = $Scopes -join ' '
103+
state = $state
104+
}
105+
if ($SelectAccount) {
106+
$parameters.prompt = 'select_account'
107+
}
108+
109+
$paramStrings = foreach ($pair in $parameters.GetEnumerator()) {
110+
$pair.Key, ([System.Web.HttpUtility]::UrlEncode($pair.Value)) -join '='
111+
}
112+
$uriFinal = $uri + ($paramStrings -join '&')
113+
Write-Verbose "Authorize Uri: $uriFinal"
114+
115+
$redirectTo = 'https://raw.githubusercontent.com/FriedrichWeinmann/MiniGraph/master/nothing-to-see-here.txt'
116+
if ((Get-Random -Minimum 10 -Maximum 99) -eq 66) {
117+
$redirectTo = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
118+
}
119+
120+
# Start local server to catch the redirect
121+
$http = [System.Net.HttpListener]::new()
122+
$http.Prefixes.Add("$redirectUri/")
123+
try { $http.Start() }
124+
catch { Invoke-TerminatingException -Cmdlet $PSCmdlet -Message "Failed to create local http listener on port $LocalPort. Use -LocalPort to select a different port. $_" -Category OpenError }
125+
126+
# Execute in default browser
127+
& $Browser $uriFinal
128+
129+
# Get Result
130+
$task = $http.GetContextAsync()
131+
$authorizationCode, $stateReturn, $sessionState = $null
132+
try {
133+
while (-not $task.IsCompleted) {
134+
Start-Sleep -Milliseconds 200
135+
}
136+
$context = $task.Result
137+
$context.Response.Redirect($redirectTo)
138+
$context.Response.Close()
139+
$authorizationCode, $stateReturn, $sessionState = $context.Request.Url.Query -split "&"
140+
}
141+
finally {
142+
$http.Stop()
143+
$http.Dispose()
144+
}
145+
146+
if (-not $stateReturn) {
147+
Invoke-TerminatingException -Cmdlet $PSCmdlet -Message "Authentication failed (see browser for details)" -Category AuthenticationError
148+
}
149+
150+
if ($state -ne $stateReturn.Split("=")[1]) {
151+
Invoke-TerminatingException -Cmdlet $PSCmdlet -Message "Received invalid authentication result. Likely returned from another flow redirecting to the same local port!" -Category InvalidOperation
152+
}
153+
154+
$actualAuthorizationCode = $authorizationCode.Split("=")[1]
155+
156+
$body = @{
157+
client_id = $ClientID
158+
scope = $actualScopes -join " "
159+
code = $actualAuthorizationCode
160+
redirect_uri = $redirectUri
161+
grant_type = 'authorization_code'
162+
}
163+
$uri = "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token"
164+
try { $authResponse = Invoke-RestMethod -Method Post -Uri $uri -Body $body -ErrorAction Stop }
165+
catch {
166+
if ($_ -notmatch '"error":\s*"invalid_client"') { Invoke-TerminatingException -Cmdlet $PSCmdlet -ErrorRecord $_ }
167+
Invoke-TerminatingException -Cmdlet $PSCmdlet -Message "The App Registration $ClientID has not been configured correctly. Ensure you have a 'Mobile and desktop applications' platform with redirect to 'http://localhost' configured (and not a 'Web' Platform). $_" -Category $_.CategoryInfo.Category
168+
}
169+
$script:token = $authResponse.access_token
170+
171+
Set-ReconnectInfo -BoundParameters $PSBoundParameters -NoReconnect:$NoReconnect -RefreshToken $authResponse.refresh_token
172+
}
173+
}

MiniGraph/functions/Connect-GraphCertificate.ps1

+19-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
.PARAMETER ClientID
1616
The ClientID / ApplicationID of the application to connect as.
1717
18+
.PARAMETER Scopes
19+
The scopes to request when connecting.
20+
IN Application flows, this only determines the service for which to retrieve the scopes already configured on the App Registration.
21+
Defaults to graph API.
22+
23+
.PARAMETER NoReconnect
24+
Disables automatic reconnection.
25+
By default, MiniGraph will automatically try to reaquire a new token before the old one expires.
26+
1827
.EXAMPLE
1928
PS C:\> $cert = Get-Item -Path 'Cert:\CurrentUser\My\082D5CB4BA31EED7E2E522B39992E34871C92BF5'
2029
PS C:\> Connect-GraphCertificate -TenantID '0639f07d-76e1-49cb-82ac-abcdefabcdefa' -ClientID '0639f07d-76e1-49cb-82ac-1234567890123' -Certificate $cert
@@ -40,7 +49,13 @@
4049

4150
[Parameter(Mandatory = $true)]
4251
[string]
43-
$ClientID
52+
$ClientID,
53+
54+
[string[]]
55+
$Scopes = 'https://graph.microsoft.com/.default',
56+
57+
[switch]
58+
$NoReconnect
4459
)
4560

4661
$jwtHeader = @{
@@ -66,7 +81,7 @@
6681
client_id = $ClientID
6782
client_assertion = $jwt
6883
client_assertion_type = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
69-
scope = 'https://graph.microsoft.com/.default'
84+
scope = $Scopes -join ' '
7085
grant_type = 'client_credentials'
7186
}
7287
$header = @{
@@ -75,4 +90,6 @@
7590
$uri = "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token"
7691
try { $script:token = (Invoke-RestMethod -Uri $uri -Method Post -Body $body -Headers $header -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop).access_token }
7792
catch { $PSCmdlet.ThrowTerminatingError($_) }
93+
94+
Set-ReconnectInfo -BoundParameters $PSBoundParameters -NoReconnect:$NoReconnect
7895
}

MiniGraph/functions/Connect-GraphClientSecret.ps1

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
The resource the token grants access to.
2323
Generally doesn't need to be changed from the default 'https://graph.microsoft.com/'
2424
Only needed when connecting to another service.
25+
26+
.PARAMETER NoReconnect
27+
Disables automatic reconnection.
28+
By default, MiniGraph will automatically try to reaquire a new token before the old one expires.
2529
2630
.EXAMPLE
2731
PS C:\> Connect-GraphClientSecret -ClientID '<ClientID>' -TenantID '<TenantID>' -ClientSecret $secret
@@ -46,7 +50,10 @@
4650
$Scopes = 'https://graph.microsoft.com/.default',
4751

4852
[string]
49-
$Resource = 'https://graph.microsoft.com/'
53+
$Resource = 'https://graph.microsoft.com/',
54+
55+
[switch]
56+
$NoReconnect
5057
)
5158

5259
process {
@@ -60,5 +67,7 @@
6067
try { $authResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$TenantId/oauth2/token" -Body $body -ErrorAction Stop }
6168
catch { $PSCmdlet.ThrowTerminatingError($_) }
6269
$script:token = $authResponse.access_token
70+
71+
Set-ReconnectInfo -BoundParameters $PSBoundParameters -NoReconnect:$NoReconnect
6372
}
6473
}

MiniGraph/functions/Connect-GraphCredential.ps1

+10-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
2121
.PARAMETER Scopes
2222
The permission scopes to request.
23+
24+
.PARAMETER NoReconnect
25+
Disables automatic reconnection.
26+
By default, MiniGraph will automatically try to reaquire a new token before the old one expires.
2327
2428
.EXAMPLE
2529
PS C:\> Connect-GraphCredential -Credential [email protected] -ClientID $client -TenantID $tenant -Scopes 'user.read','user.readbasic.all'
@@ -41,7 +45,10 @@
4145
$TenantID,
4246

4347
[string[]]
44-
$Scopes = 'user.read'
48+
$Scopes = 'user.read',
49+
50+
[switch]
51+
$NoReconnect
4552
)
4653

4754
$request = @{
@@ -55,4 +62,6 @@
5562
try { $answer = Invoke-RestMethod -Method POST -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Body $request -ErrorAction Stop }
5663
catch { $PSCmdlet.ThrowTerminatingError($_) }
5764
$script:token = $answer.access_token
65+
66+
Set-ReconnectInfo -BoundParameters $PSBoundParameters -NoReconnect:$NoReconnect
5867
}

0 commit comments

Comments
 (0)