1+ <#
2+
3+ .COPYRIGHT
4+ Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
5+ See LICENSE in the project root for license information.
6+
7+ #>
8+
9+ # ###################################################
10+
11+ function Get-AuthToken {
12+
13+ <#
14+ . SYNOPSIS
15+ This function is used to authenticate with the Graph API REST interface
16+ . DESCRIPTION
17+ The function authenticate with the Graph API Interface with the tenant name
18+ . EXAMPLE
19+ Get-AuthToken
20+ Authenticates you with the Graph API interface
21+ . NOTES
22+ NAME: Get-AuthToken
23+ #>
24+
25+ [cmdletbinding ()]
26+
27+ param
28+ (
29+ [Parameter (Mandatory = $true )]
30+ $User
31+ )
32+
33+ $userUpn = New-Object " System.Net.Mail.MailAddress" - ArgumentList $User
34+
35+ $tenant = $userUpn.Host
36+
37+ Write-Host " Checking for AzureAD module..."
38+
39+ $AadModule = Get-Module - Name " AzureAD" - ListAvailable
40+
41+ if ($AadModule -eq $null ) {
42+
43+ Write-Host " AzureAD PowerShell module not found, looking for AzureADPreview"
44+ $AadModule = Get-Module - Name " AzureADPreview" - ListAvailable
45+
46+ }
47+
48+ if ($AadModule -eq $null ) {
49+ write-host
50+ write-host " AzureAD Powershell module not installed..." -f Red
51+ write-host " Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow
52+ write-host " Script can't continue..." -f Red
53+ write-host
54+ exit
55+ }
56+
57+ # Getting path to ActiveDirectory Assemblies
58+ # If the module count is greater than 1 find the latest version
59+
60+ if ($AadModule.count -gt 1 ) {
61+
62+ $Latest_Version = ($AadModule | select version | Sort-Object )[-1 ]
63+
64+ $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
65+
66+ # Checking if there are multiple versions of the same module found
67+
68+ if ($AadModule.count -gt 1 ) {
69+
70+ $aadModule = $AadModule | select - Unique
71+
72+ }
73+
74+ $adal = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
75+ $adalforms = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
76+
77+ }
78+
79+ else {
80+
81+ $adal = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
82+ $adalforms = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
83+
84+ }
85+
86+ [System.Reflection.Assembly ]::LoadFrom($adal ) | Out-Null
87+
88+ [System.Reflection.Assembly ]::LoadFrom($adalforms ) | Out-Null
89+
90+ $clientId = " d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
91+
92+ $redirectUri = " urn:ietf:wg:oauth:2.0:oob"
93+
94+ $resourceAppIdURI = " https://graph.microsoft.com"
95+
96+ $authority = " https://login.microsoftonline.com/$Tenant "
97+
98+ try {
99+
100+ $authContext = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" - ArgumentList $authority
101+
102+ # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx
103+ # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession
104+
105+ $platformParameters = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" - ArgumentList " Auto"
106+
107+ $userId = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" - ArgumentList ($User , " OptionalDisplayableId" )
108+
109+ $authResult = $authContext.AcquireTokenAsync ($resourceAppIdURI , $clientId , $redirectUri , $platformParameters , $userId ).Result
110+
111+ # If the accesstoken is valid then create the authentication header
112+
113+ if ($authResult.AccessToken ) {
114+
115+ # Creating header for Authorization token
116+
117+ $authHeader = @ {
118+ ' Content-Type' = ' application/json'
119+ ' Authorization' = " Bearer " + $authResult.AccessToken
120+ ' ExpiresOn' = $authResult.ExpiresOn
121+ }
122+
123+ return $authHeader
124+
125+ }
126+
127+ else {
128+
129+ Write-Host
130+ Write-Host " Authorization Access Token is null, please re-run authentication..." - ForegroundColor Red
131+ Write-Host
132+ break
133+
134+ }
135+
136+ }
137+
138+ catch {
139+
140+ write-host $_.Exception.Message -f Red
141+ write-host $_.Exception.ItemName -f Red
142+ write-host
143+ break
144+
145+ }
146+
147+ }
148+
149+ # ###################################################
150+
151+ Function Get-ManagedAppPolicyRegistrationSummary () {
152+
153+ <#
154+ . SYNOPSIS
155+ This function is used to download App Protection Report for iOS and Android.
156+ . DESCRIPTION
157+ The function connects to the Graph API Interface and gets the ManagedAppRegistrationSummary
158+ . EXAMPLE
159+ Get-ManagedAppPolicyRegistrationSummary -ReportType Android_iOS
160+ Returns any managed app policies configured in Intune
161+ . NOTES
162+ NAME: Get-ManagedAppPolicyRegistrationSummary
163+ #>
164+
165+ [cmdletbinding ()]
166+
167+ param
168+ (
169+ [ValidateSet (" Android_iOS" , " WIP_WE" , " WIP_MDM" )]
170+ $ReportType ,
171+ $NextPage
172+ )
173+
174+ $graphApiVersion = " Beta"
175+ $Stoploop = $false
176+ [int ]$Retrycount = " 0"
177+ do {
178+ try {
179+
180+ if ($ReportType -eq " " -or $ReportType -eq $null ) {
181+ $ReportType = " Android_iOS"
182+
183+ }
184+ elseif ($ReportType -eq " Android_iOS" ) {
185+
186+ $Resource = " /deviceAppManagement/managedAppStatuses('appregistrationsummary')?fetch=6000&policyMode=0&columns=DisplayName,UserEmail,ApplicationName,ApplicationInstanceId,ApplicationVersion,DeviceName,DeviceType,DeviceManufacturer,DeviceModel,AndroidPatchVersion,AzureADDeviceId,MDMDeviceID,Platform,PlatformVersion,ManagementLevel,PolicyName,LastCheckInDate"
187+ if ($NextPage -ne " " -and $NextPage -ne $null ) {
188+ $Resource += " &seek=$NextPage "
189+ }
190+ $uri = " https://graph.microsoft.com/$graphApiVersion /$ ( $Resource ) "
191+ Invoke-RestMethod - Uri $uri - Headers $authToken - Method Get
192+
193+ }
194+
195+ elseif ($ReportType -eq " WIP_WE" ) {
196+
197+ $Resource = " deviceAppManagement/managedAppStatuses('windowsprotectionreport')"
198+ if ($NextPage -ne " " -and $NextPage -ne $null ) {
199+ $Resource += " &seek=$NextPage "
200+ }
201+ $uri = " https://graph.microsoft.com/$graphApiVersion /$ ( $Resource ) "
202+ Invoke-RestMethod - Uri $uri - Headers $authToken - Method Get
203+
204+ }
205+
206+ elseif ($ReportType -eq " WIP_MDM" ) {
207+
208+ $Resource = " deviceAppManagement/mdmWindowsInformationProtectionPolicies"
209+
210+ $uri = " https://graph.microsoft.com/$graphApiVersion /$ ( $Resource ) "
211+ Invoke-RestMethod - Uri $uri - Headers $authToken - Method Get
212+
213+ }
214+ $Stoploop = $true
215+ }
216+
217+ catch {
218+
219+ $ex = $_.Exception
220+
221+ # Retry 4 times if 503 service time out
222+ if ($ex.Response.StatusCode.value__ -eq " 503" ) {
223+ $Retrycount = $Retrycount + 1
224+ $Stoploop = $Retrycount -gt 3
225+ if ($Stoploop -eq $false ) {
226+ Start-Sleep - Seconds 5
227+ continue
228+ }
229+ }
230+ $errorResponse = $ex.Response.GetResponseStream ()
231+ $reader = New-Object System.IO.StreamReader($errorResponse )
232+ $reader.BaseStream.Position = 0
233+ $reader.DiscardBufferedData ()
234+ $responseBody = $reader.ReadToEnd ();
235+ Write-Host " Response content:`n $responseBody " -f Red
236+ Write-Error " Request to $Uri failed with HTTP Status $ ( $ex.Response.StatusCode ) $ ( $ex.Response.StatusDescription ) "
237+ write-host
238+ $Stoploop = $true
239+ break
240+ }
241+ }
242+ while ($Stoploop -eq $false )
243+
244+ }
245+
246+ # ###################################################
247+
248+ Function Test-AuthToken (){
249+
250+ # Checking if authToken exists before running authentication
251+ if ($global :authToken ) {
252+
253+ # Setting DateTime to Universal time to work in all timezones
254+ $DateTime = (Get-Date ).ToUniversalTime()
255+
256+ # If the authToken exists checking when it expires
257+ $TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime ).Minutes
258+
259+ if ($TokenExpires -le 0 ) {
260+
261+ write-host " Authentication Token expired" $TokenExpires " minutes ago" - ForegroundColor Yellow
262+ write-host
263+
264+ # Defining User Principal Name if not present
265+
266+ if ($User -eq $null -or $User -eq " " ) {
267+
268+ $global :User = Read-Host - Prompt " Please specify your user principal name for Azure Authentication"
269+ Write-Host
270+
271+ }
272+
273+ $global :authToken = Get-AuthToken - User $User
274+
275+ }
276+ }
277+
278+ # Authentication doesn't exist, calling Get-AuthToken function
279+
280+ else {
281+
282+ if ($User -eq $null -or $User -eq " " ) {
283+
284+ $global :User = Read-Host - Prompt " Please specify your user principal name for Azure Authentication"
285+ Write-Host
286+
287+ }
288+
289+ # Getting the authorization token
290+ $global :authToken = Get-AuthToken - User $User
291+
292+ }
293+ }
294+
295+ # ###################################################
296+
297+ Test-AuthToken
298+
299+ # ###################################################
300+
301+ Write-Host
302+
303+ $ExportPath = Read-Host - Prompt " Please specify a path to export the policy data to e.g. C:\IntuneOutput"
304+
305+ # If the directory path doesn't exist prompt user to create the directory
306+
307+ if (! (Test-Path " $ExportPath " )) {
308+
309+ Write-Host
310+ Write-Host " Path '$ExportPath ' doesn't exist, do you want to create this directory? Y or N?" - ForegroundColor Yellow
311+
312+ $Confirm = read-host
313+
314+ if ($Confirm -eq " y" -or $Confirm -eq " Y" ) {
315+
316+ new-item - ItemType Directory - Path " $ExportPath " | Out-Null
317+ Write-Host
318+
319+ }
320+
321+ else {
322+
323+ Write-Host " Creation of directory path was cancelled..." - ForegroundColor Red
324+ Write-Host
325+ break
326+
327+ }
328+
329+ }
330+
331+ Write-Host
332+
333+ # ###################################################
334+
335+ $AppType = Read-Host - Prompt " Please specify the type of report [Android_iOS, WIP_WE, WIP_MDM]"
336+
337+ if ($AppType -eq " Android_iOS" -or $AppType -eq " WIP_WE" -or $AppType -eq " WIP_MDM" ) {
338+
339+ Write-Host
340+ write-host " Running query against Microsoft Graph to download App Protection Report for '$AppType '.." -f Yellow
341+
342+ $ofs = ' ,'
343+ $stream = [System.IO.StreamWriter ]::new(" $ExportPath \AppRegistrationSummary_$AppType .csv" , $false , [System.Text.Encoding ]::UTF8)
344+ $ManagedAppPolicies = Get-ManagedAppPolicyRegistrationSummary - ReportType $AppType
345+ $stream.WriteLine ([string ]($ManagedAppPolicies.content.header | % {$_.columnName } ))
346+
347+ do {
348+ Test-AuthToken
349+
350+ write-host " Your data is being downloaded for '$AppType '..."
351+ $MoreItem = $ManagedAppPolicies.content.skipToken -ne " " -and $ManagedAppPolicies.content.skipToken -ne $null
352+
353+ foreach ($SummaryItem in $ManagedAppPolicies.content.body ) {
354+
355+ $stream.WriteLine ([string ]($SummaryItem.values -replace " ," , " ." ))
356+ }
357+
358+ if ($MoreItem ){
359+
360+ $ManagedAppPolicies = Get-ManagedAppPolicyRegistrationSummary - ReportType $AppType - NextPage ($ManagedAppPolicies.content.skipToken )
361+ }
362+
363+ } while ($MoreItem )
364+
365+ $stream.close ()
366+
367+ write-host
368+
369+ }
370+
371+ else {
372+
373+ Write-Host " AppType isn't a valid option..." - ForegroundColor Red
374+ Write-Host
375+
376+ }
0 commit comments