Closed thommck closed 3 years ago
The Paging sample shows how to page against managed Devices, you can use the same function in the hardware get script to complete paging. https://github.com/microsoftgraph/powershell-intune-samples/blob/master/Paging/ManagedDevices_Get_Paging.ps1
OK, I have got this working now, it just wasn't clear what bit I should be copying where. Is there a reason you just don't make this the default in the script? Why would you want it to stop at 1000 (or at least flash a big warning saying about the limit).
For others looking at this thread, I replaced the following line (around line 215):
(Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value
with the paging code:
<# Original code
(Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value
#>
<# New code below #>
$DevicesResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get)
$Devices = $DevicesResponse.value
$DevicesNextLink = $DevicesResponse."@odata.nextLink"
while ($DevicesNextLink -ne $null){
$DevicesResponse = (Invoke-RestMethod -Uri $DevicesNextLink -Headers $authToken -Method Get)
$DevicesNextLink = $DevicesResponse."@odata.nextLink"
$Devices += $DevicesResponse.value
There are two things that should be standard in these samples: 1) If you get a collection you need to page through the response 2) If it is not a collection, then the response is the data. If it is a collection, then the response is the metadata, and the collection is response.value.
I added this code in the ManagedDevices_Hardware_Get.ps1 at line 215 where I do see the old code referenced. However, I am getting an error.
ManagedDevices_Hardware_Get.ps1:246 char:2
There you are “paging modified” PS script.
<#
.COPYRIGHT Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information.
####################################################
function Get-AuthToken {
<# .SYNOPSIS This function is used to authenticate with the Graph API REST interface .DESCRIPTION The function authenticate with the Graph API Interface with the tenant name .EXAMPLE Get-AuthToken Authenticates you with the Graph API interface .NOTES NAME: Get-AuthToken
[cmdletbinding()]
param ( [Parameter(Mandatory=$true)] $User )
$userUpn = New-Object "System.Net.Mail.MailAddress" -ArgumentList $User
$tenant = $userUpn.Host
Write-Host "Checking for AzureAD module..."
$AadModule = Get-Module -Name "AzureAD" -ListAvailable
if ($AadModule -eq $null) {
Write-Host "AzureAD PowerShell module not found, looking for AzureADPreview"
$AadModule = Get-Module -Name "AzureADPreview" -ListAvailable
}
if ($AadModule -eq $null) {
write-host
write-host "AzureAD Powershell module not installed..." -f Red
write-host "Install by running 'Install-Module AzureAD' or 'Install-Module AzureADPreview' from an elevated PowerShell prompt" -f Yellow
write-host "Script can't continue..." -f Red
write-host
exit
}
if($AadModule.count -gt 1){
$Latest_Version = ($AadModule | select version | Sort-Object)[-1]
$aadModule = $AadModule | ? { $_.version -eq $Latest_Version.version }
# Checking if there are multiple versions of the same module found
if($AadModule.count -gt 1){
$aadModule = $AadModule | select -Unique
}
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
else {
$adal = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = Join-Path $AadModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
}
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$clientId = "d1ddf0e4-d672-4dae-b554-9d5bdfd93547"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$Tenant"
try {
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
# https://msdn.microsoft.com/en-us/library/azure/microsoft.identitymodel.clients.activedirectory.promptbehavior.aspx
# Change the prompt behaviour to force credentials each time: Auto, Always, Never, RefreshSession
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Auto"
$userId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($User, "OptionalDisplayableId")
$authResult = $authContext.AcquireTokenAsync($resourceAppIdURI,$clientId,$redirectUri,$platformParameters,$userId).Result
# If the accesstoken is valid then create the authentication header
if($authResult.AccessToken){
# Creating header for Authorization token
$authHeader = @{
'Content-Type'='application/json'
'Authorization'="Bearer " + $authResult.AccessToken
'ExpiresOn'=$authResult.ExpiresOn
}
return $authHeader
}
else {
Write-Host
Write-Host "Authorization Access Token is null, please re-run authentication..." -ForegroundColor Red
Write-Host
break
}
}
catch {
write-host $_.Exception.Message -f Red
write-host $_.Exception.ItemName -f Red
write-host
break
}
}
####################################################
Function Get-ManagedDevices(){
<# .SYNOPSIS This function is used to get Intune Managed Devices from the Graph API REST interface .DESCRIPTION The function connects to the Graph API Interface and gets any Intune Managed Device .EXAMPLE Get-ManagedDevices Returns all managed devices but excludes EAS devices registered within the Intune Service .EXAMPLE Get-ManagedDevices -IncludeEAS Returns all managed devices including EAS devices registered within the Intune Service .NOTES NAME: Get-ManagedDevices
[cmdletbinding()]
param ( [switch]$IncludeEAS, [switch]$ExcludeMDM )
$graphApiVersion = "beta" $Resource = "deviceManagement/managedDevices"
try {
$Count_Params = 0
if($IncludeEAS.IsPresent){ $Count_Params++ }
if($ExcludeMDM.IsPresent){ $Count_Params++ }
if($Count_Params -gt 1){
write-warning "Multiple parameters set, specify a single parameter -IncludeEAS, -ExcludeMDM or no parameter against the function"
Write-Host
break
}
elseif($IncludeEAS){
$uri = "https://graph.microsoft.com/$graphApiVersion/$Resource"
}
elseif($ExcludeMDM){
$uri = "https://graph.microsoft.com/$graphApiVersion/$Resource`?`$filter=managementAgent eq 'eas'"
}
else {
$uri = "https://graph.microsoft.com/$graphApiVersion/$Resource`?`$filter=managementAgent eq 'mdm' and managementAgent eq 'easmdm' and managementAgent eq 'googleCloudDevicePolicyController'"
Write-Warning "EAS Devices are excluded by default, please use -IncludeEAS if you want to include those devices"
Write-Host
}
<# Original code
(Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value
<# New code below #> $DevicesResponse = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get)
$Devices = $DevicesResponse.value
$DevicesNextLink = $DevicesResponse."@odata.nextLink"
while ($DevicesNextLink -ne $null){
$DevicesResponse = (Invoke-RestMethod -Uri $DevicesNextLink -Headers $authToken -Method Get)
$DevicesNextLink = $DevicesResponse."@odata.nextLink"
$Devices += $DevicesResponse.value
}
$Devices
}
catch {
$ex = $_.Exception
$errorResponse = $ex.Response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($errorResponse)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
$responseBody = $reader.ReadToEnd();
Write-Host "Response content:`n$responseBody" -f Red
Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
write-host
break
}
}
####################################################
write-host
if($global:authToken){
# Setting DateTime to Universal time to work in all timezones
$DateTime = (Get-Date).ToUniversalTime()
# If the authToken exists checking when it expires
$TokenExpires = ($authToken.ExpiresOn.datetime - $DateTime).Minutes
if($TokenExpires -le 0){
write-host "Authentication Token expired" $TokenExpires "minutes ago" -ForegroundColor Yellow
write-host
# Defining User Principal Name if not present
if($User -eq $null -or $User -eq ""){
$User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication"
Write-Host
}
$global:authToken = Get-AuthToken -User $User
}
}
else {
if($User -eq $null -or $User -eq ""){
$User = Read-Host -Prompt "Please specify your user principal name for Azure Authentication"
Write-Host
}
$global:authToken = Get-AuthToken -User $User
}
####################################################
$ExportPath = Read-Host -Prompt "Please specify a path to export Managed Devices hardware data to e.g. C:\IntuneOutput"
# If the directory path doesn't exist prompt user to create the directory
if(!(Test-Path "$ExportPath")){
Write-Host
Write-Host "Path '$ExportPath' doesn't exist, do you want to create this directory? Y or N?" -ForegroundColor Yellow
$Confirm = read-host
if($Confirm -eq "y" -or $Confirm -eq "Y"){
new-item -ItemType Directory -Path "$ExportPath" | Out-Null
Write-Host
}
else {
Write-Host "Creation of directory path was cancelled..." -ForegroundColor Red
Write-Host
break
}
}
Write-Host
####################################################
$Devices = Get-ManagedDevices
if($Devices){
$Results = @()
foreach($Device in $Devices){
$DeviceID = $Device.id
Write-Host "Device found:" $Device.deviceName -ForegroundColor Yellow
Write-Host
$uri = "https://graph.microsoft.com/beta/deviceManagement/manageddevices('$DeviceID')?`$select=hardwareinformation,iccid,udid,ethernetMacAddress"
$DeviceInfo = (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get)
$DeviceNoHardware = $Device | select * -ExcludeProperty hardwareInformation,deviceActionResults,userId,imei,manufacturer,model,isSupervised,isEncrypted,serialNumber,meid,subscriberCarrier,iccid,udid,ethernetMacAddress
$HardwareExcludes = $DeviceInfo.hardwareInformation | select * -ExcludeProperty sharedDeviceCachedUsers,phoneNumber
$OtherDeviceInfo = $DeviceInfo | select iccid,udid,ethernetMacAddress
$Object = New-Object System.Object
foreach($Property in $DeviceNoHardware.psobject.Properties){
$Object | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value
}
foreach($Property in $HardwareExcludes.psobject.Properties){
$Object | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value
}
foreach($Property in $OtherDeviceInfo.psobject.Properties){
$Object | Add-Member -MemberType NoteProperty -Name $Property.Name -Value $Property.Value
}
$Results += $Object
$Object
}
$Date = get-date
$Output = "ManagedDeviceHardwareInfo_" + $Date.Day + "-" + $Date.Month + "-" + $Date.Year + "_" + $Date.Hour + "-" + $Date.Minute
# Exporting Data to CSV file in provided directory
$Results | Export-Csv "$ExportPath\$Output.csv" -NoTypeInformation
write-host "CSV created in $ExportPath\$Output.csv..." -f cyan
}
else {
write-host "No Intune Managed Devices found..." -f green Write-Host
}
I appreciate there are similar issues that reference this issue on other scripts (fix being to use the paging sample https://github.com/microsoftgraph/powershell-intune-samples/tree/master/Paging). However, I can't figure out how to integrate that into the ManagedDevices_Hardware_Get.ps1 script. It would be great to include this limit in the README as I don't think most people coming from PowerShell will understand it. Can you include this by default or add it as a parameter please?