1+
2+ <#
3+
4+ .COPYRIGHT
5+ Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
6+ See LICENSE in the project root for license information.
7+
8+ #>
9+
10+ param (
11+
12+ [Parameter (Mandatory = $true , HelpMessage = " File path and name for output of expiring devices" )]
13+ $OutputFile
14+
15+ )
16+
17+ # ###################################################
18+
19+ function Get-AuthToken {
20+
21+ <#
22+ . SYNOPSIS
23+ This function is used to authenticate with the Graph API REST interface
24+ . DESCRIPTION
25+ The function authenticate with the Graph API Interface with the tenant name
26+ . EXAMPLE
27+ Get-AuthToken
28+ Authenticates you with the Graph API interface
29+ . NOTES
30+ NAME: Get-AuthToken
31+ #>
32+
33+ [cmdletbinding ()]
34+
35+ param
36+ (
37+ [Parameter (Mandatory = $true )]
38+ $User
39+ )
40+
41+ $userUpn = New-Object " System.Net.Mail.MailAddress" - ArgumentList $User
42+
43+ $tenant = $userUpn.Host
44+
45+ Write-Host " Checking for AzureAD module..."
46+
47+ $AadModule = Get-Module - Name " AzureAD" - ListAvailable
48+
49+ if ($AadModule -eq $null ) {
50+
51+ Write-Host " AzureAD PowerShell module not found, looking for AzureADPreview"
52+ $AadModule = Get-Module - Name " AzureADPreview" - ListAvailable
53+
54+ }
55+
56+ if ($AadModule -eq $null ) {
57+ write-host
58+ write-host " AzureAD Powershell module not installed..." -f Red
59+ write-host " Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow
60+ write-host " Script can't continue..." -f Red
61+ write-host
62+ exit
63+ }
64+
65+ # Getting path to ActiveDirectory Assemblies
66+ # If the module count is greater than 1 find the latest version
67+
68+ if ($AadModule.count -gt 1 ){
69+
70+ $Latest_Version = ($AadModule | select version | Sort-Object )[-1 ]
71+
72+ $aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
73+
74+ # Checking if there are multiple versions of the same module found
75+
76+ if ($AadModule.count -gt 1 ){
77+
78+ $aadModule = $AadModule | select - Unique
79+
80+ }
81+
82+ $adal = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
83+ $adalforms = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
84+
85+ }
86+
87+ else {
88+
89+ $adal = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
90+ $adalforms = Join-Path $AadModule.ModuleBase " Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
91+
92+ }
93+
94+ [System.Reflection.Assembly ]::LoadFrom($adal ) | Out-Null
95+
96+ [System.Reflection.Assembly ]::LoadFrom($adalforms ) | Out-Null
97+
98+ $clientId = " d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
99+
100+ $redirectUri = " urn:ietf:wg:oauth:2.0:oob"
101+
102+ $resourceAppIdURI = " https://graph.microsoft.com"
103+
104+ $authority = " https://login.microsoftonline.com/$Tenant "
105+
106+ try {
107+
108+ $authContext = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" - ArgumentList $authority
109+
110+ # https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx
111+ # Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession
112+
113+ $platformParameters = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" - ArgumentList " Auto"
114+
115+ $userId = New-Object " Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" - ArgumentList ($User , " OptionalDisplayableId" )
116+
117+ $authResult = $authContext.AcquireTokenAsync ($resourceAppIdURI , $clientId , $redirectUri , $platformParameters , $userId ).Result
118+
119+ # If the accesstoken is valid then create the authentication header
120+
121+ if ($authResult.AccessToken ){
122+
123+ # Creating header for Authorization token
124+
125+ $authHeader = @ {
126+ ' Content-Type' = ' application/json'
127+ ' Authorization' = " Bearer " + $authResult.AccessToken
128+ ' ExpiresOn' = $authResult.ExpiresOn
129+ }
130+
131+ return $authHeader
132+
133+ }
134+
135+ else {
136+
137+ Write-Host
138+ Write-Host " Authorization Access Token is null, please re-run authentication..." - ForegroundColor Red
139+ Write-Host
140+ break
141+
142+ }
143+
144+ }
145+
146+ catch {
147+
148+ write-host $_.Exception.Message -f Red
149+ write-host $_.Exception.ItemName -f Red
150+ write-host
151+ break
152+
153+ }
154+
155+ }
156+
157+ # ###################################################
158+
159+ function Get-MsGraphCollection {
160+
161+ param
162+ (
163+ [Parameter (Mandatory = $true )]
164+ $Uri ,
165+
166+ [Parameter (Mandatory = $true )]
167+ $AuthHeader
168+ )
169+
170+ $Collection = @ ()
171+ $NextLink = $Uri
172+ $CertExpiration = [datetime ]' 2020-07-12 12:00:00' # (Get-Date -Year 2019 -Month 4 -Day 21 -Hour 14 -Minute 48)
173+
174+ do {
175+
176+ try {
177+
178+ Write-Host " GET $NextLink "
179+ $Result = Invoke-RestMethod - Method Get - Uri $NextLink - Headers $AuthHeader
180+
181+ foreach ($d in $Result.value )
182+ {
183+ if ([datetime ]($d.managementCertificateExpirationDate ) -le $CertExpiration )
184+ {
185+ $Collection += $d
186+ }
187+ }
188+ $NextLink = $Result .' @odata.nextLink'
189+ }
190+
191+ catch {
192+
193+ $ResponseStream = $_.Exception.Response.GetResponseStream ()
194+ $ResponseReader = New-Object System.IO.StreamReader $ResponseStream
195+ $ResponseContent = $ResponseReader.ReadToEnd ()
196+ Write-Host " Request Failed: $ ( $_.Exception.Message ) `n $ ( $_.ErrorDetails ) "
197+ Write-Host " Request URL: $NextLink "
198+ Write-Host " Response Content:`n $ResponseContent "
199+ break
200+
201+ }
202+
203+ } while ($NextLink -ne $null )
204+
205+ return $Collection
206+ }
207+
208+ # ###################################################
209+
210+ # region Authentication
211+
212+ write-host
213+
214+ # Checking if authToken exists before running authentication
215+ if ($global :authToken ){
216+
217+ # Setting DateTime to Universal time to work in all timezones
218+ $DateTime = (Get-Date ).ToUniversalTime()
219+
220+ # If the authToken exists checking when it expires
221+ $TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime ).Minutes
222+
223+ if ($TokenExpires -le 0 ){
224+
225+ write-host " Authentication Token expired" $TokenExpires " minutes ago" - ForegroundColor Yellow
226+ write-host
227+
228+ # Defining User Principal Name if not present
229+
230+ if ($User -eq $null -or $User -eq " " ){
231+
232+ $User = Read-Host - Prompt " Please specify your user principal name for Azure Authentication"
233+ Write-Host
234+
235+ }
236+
237+ $global :authToken = Get-AuthToken - User $User
238+
239+ }
240+ }
241+
242+ # Authentication doesn't exist, calling Get-AuthToken function
243+
244+ else {
245+
246+ if ($User -eq $null -or $User -eq " " ){
247+
248+ $User = Read-Host - Prompt " Please specify your user principal name for Azure Authentication"
249+ Write-Host
250+
251+ }
252+
253+ # Getting the authorization token
254+ $global :authToken = Get-AuthToken - User $User
255+
256+ }
257+
258+ # endregion
259+
260+ # ###################################################
261+
262+ $uri = " https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$ filter=((managementAgent%20eq%20%27mdm%27%20or%20managementAgent%20eq%20%27easmdm%27%20or%20managementAgent%20eq%20%27configurationmanagerclientmdm%27%20or%20managementAgent%20eq%20%27configurationmanagerclientmdmeas%27)%20and%20managementState%20eq%20%27managed%27)"
263+
264+ $devices = Get-MsGraphCollection - Uri $uri - AuthHeader $authToken
265+
266+ Write-Host
267+ Write-Host " Found" $devices.Count " devices:"
268+ Write-Host " Writing results to" $OutputFile - ForegroundColor Cyan
269+
270+ ($devices | Select-Object Id, DeviceName, DeviceType, IMEI, UserPrincipalName, SerialNumber, LastSyncDateTime, ManagementCertificateExpirationDate) | Export-Csv - Path $OutputFile - NoTypeInformation
271+
272+ $devices | Select-Object Id, DeviceName, DeviceType, IMEI, UserPrincipalName, SerialNumber, LastSyncDateTime, ManagementCertificateExpirationDate
273+
274+ Write-Host " Results written to" $OutputFile - ForegroundColor Yellow
0 commit comments