UGDSB.PS.Graph.psm1

#Region '.\Public\Add-GraphGroupMember.ps1' 0
function Add-GraphGroupMember{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$groupId,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string[]]$ids
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # Get Graph Headers for Call
  $headers = Get-GraphHeader  
  try{
    $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
    $batches = [System.Collections.Generic.List[PSCustomObject]]@()
    for($i = 1; $i -le $ids.Count; ++$i){
      $obj = [PSCustomObject]@{
        "id" = $i
        "headers" = @{
          "Content-type" = "application/json"
        }
        "method" = "POST"
        "url" = "/groups/$($groupId)/members/`$ref"
        "body" = @{
          "@odata.id" = "https://graph.microsoft.com/beta/directoryObjects/$($ids[$i-1])"
        }
      }
      $batchObj.Add($obj) | Out-Null        
      if($($i % 20) -eq 0){
        $batches.Add($batchObj) | Out-Null
        $batchObj = $null
        $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
      }
    }
    $batches.Add($batchObj) | Out-Null
    foreach($batch in $batches){
      $json = [PSCustomObject]@{
        "requests" = $batch
      } | ConvertTo-JSON -Depth 5
      $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json
    }
    
  } 
  catch{
    throw "Unable to add members. $($_.Exception.Message)"
  }  
}
#EndRegion '.\Public\Add-GraphGroupMember.ps1' 48
#Region '.\Public\Add-GraphIntuneAppAddToESP.ps1' 0
function Add-GraphIntuneAppAddToESP{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true,ParameterSetName = 'id')][ValidateNotNullOrEmpty()][string]$id,
    [Parameter(Mandatory = $true, ParameterSetName = 'displayName')][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid
  )
  # Body for JSON
  if($id){
    $currentData = Get-GraphIntuneEnrollmentStatusPage -id $id
  }
  elseif($displayName){
    $currentData = Get-GraphIntuneEnrollmentStatusPage -displayName $displayName
  }
  # Endpoint
  $endpoint = "deviceManagement/deviceEnrollmentConfigurations/$($currentData.id)"
  # Add Application to the ESP
  $currentData.selectedMobileAppIds = @("$($currentData.selectedMobileAppIds -join ','),$($applicationid)") -split ","
  $params = @{
    "@odata.type"                             = "#microsoft.graph.windows10EnrollmentCompletionPageConfiguration"
    id                                        = $currentData.id
    displayName                               = $currentData.displayName
    description                               = $currentData.description
    showInstallationProgress                  = $currentData.showInstallationProgress
    blockDeviceSetupRetryByUser               = $currentData.blockDeviceSetupRetryByUser
    allowDeviceResetOnInstallFailure          = $currentData.allowDeviceResetOnInstallFailure
    allowLogCollectionOnInstallFailure        = $currentData.allowLogCollectionOnInstallFailure
    customErrorMessage                        = $currentData.customErrorMessage
    installProgressTimeoutInMinutes           = $currentData.installProgressTimeoutInMinutes
    allowDeviceUseOnInstallFailure            = $currentData.allowDeviceUseOnInstallFailure
    selectedMobileAppIds                      = $currentData.selectedMobileAppIds
    trackInstallProgressForAutopilotOnly      = $currentData.trackInstallProgressForAutopilotOnly
    disableUserStatusTrackingAfterFirstUser   = $currentData.disableUserStatusTrackingAfterFirstUser
    roleScopeTagIds                           = $currentData.roleScopeTagIds
    allowNonBlockingAppInstallation           = $currentData.allowNonBlockingAppInstallation
    installQualityUpdates                     = $currentData.installQualityUpdates
  }
  try{
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    $headers = Get-GraphHeader
    Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body $($params | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode
  }
  catch{
    $_
  }
}
#EndRegion '.\Public\Add-GraphIntuneAppAddToESP.ps1' 47
#Region '.\Public\Add-GraphIntuneAppAssignment.ps1' 0
function Add-GraphIntuneAppAssignment{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid,
    [Parameter(Mandatory = $true)][ValidateSet("available","required","uninstall")][string]$intent,
    [Parameter(Mandatory = $false)][string[]]$groups,
    [Parameter(Mandatory = $false)][Object[]]$filters = $null,
    [Parameter(Mandatory = $false)][switch]$exclude,
    [Parameter(Mandatory = $false)][bool]$foreground = $false,
    [Parameter(Mandatory = $false)][ValidateSet("Output","Verbose")][string]$LogLevel = "Verbose"
  )
  # Default format for assignment body
  $assignment = [PSCustomObject]@{
    "@odata.type" = "#microsoft.graph.mobileAppAssignment"
    "intent" = $intent
    "target" = $null
    "settings" = $null
  }
  foreach($group in $groups){
    # Set Filter details
    $filterId = $null
    $filterType = "none"
    if($null -ne $filters.$group){
      $assignmentFilters = Get-GraphIntuneFilters
      $filterId = ($assignmentFilters | Where-Object {$_.DisplayName -eq $filters.$group.filterName}).id
      $filterType = $filters.$group.filterType
    }
    $target = [PSCustomObject]@{
      "deviceAndAppManagementAssignmentFilterId" = $filterId
      "deviceAndAppManagementAssignmentFilterType" = $filterType
    }
    # Targeting Values
    switch($group.ToLower()){
      "all users" {
        $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.allLicensedUsersAssignmentTarget"
      }
      "all devices" {
        $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.allDevicesAssignmentTarget"
      }
      default {
        if($exclude){
          $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.exclusionGroupAssignmentTarget"
        }
        else{
          $target | Add-Member -MemberType "NoteProperty" -Name "@odata.type" -Value "#microsoft.graph.groupAssignmentTarget"
        }
        try{
          $groupdetails = Get-GraphGroup -groupName $group
          $target | Add-Member -MemberType "NoteProperty" -Name "groupId" -Value $groupdetails.id
        }
        catch{
          throw "Unable to get ID of the group selected. $($_.Exception.Message)"
        }
      }
    }
    $assignment.target = $target
    # Settings Values
    if(!$exclude){
      $settings = [PSCustomObject]@{
        "@odata.type" = "#microsoft.graph.win32LobAppAssignmentSettings"
      }
      if($foreground){
        $settings | Add-Member -MemberType "NoteProperty" -Name "deliveryOptimizationPriority" -Value "foreground"
      }
      $assignment.settings = $settings
    }
    try{
      $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments"
      $headers = Get-GraphHeader
      Invoke-RestMethod -Method post -Uri $endpoint -Headers $headers -Body $($assignment | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode | Out-Null
    }
    catch{
      if(([REGEX]::Match($((($_ | ConvertFrom-Json).error.message | ConvertFrom-JSON).Message),"The MobileApp Assignment already exists")).Success){
        continue
      }
      else{
        throw $($_.Exception.Message)
      }
    }
  }
}
#EndRegion '.\Public\Add-GraphIntuneAppAssignment.ps1' 82
#Region '.\Public\Copy-GraphIntuneAppAssignments.ps1' 0
function Copy-GraphIntuneAppAssignments{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$copyapplicationid
  )
  # Get the Assignments that we will be copying
  $assignments = Get-GraphIntuneAppAssignment -applicationid $copyapplicationid
  # Loop through the assignments
  foreach($assignment in $assignments){
    $assignment = [PSCustomObject]@{
      "@odata.type" = "#microsoft.graph.mobileAppAssignment"
      "intent" = $assignment.intent
      "target" = $assignment.target
      "settings" = $assignment.settings
    }
    try{
      $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments"
      $headers = Get-GraphHeader
      Invoke-RestMethod -Method post -Uri $endpoint -Headers $headers -Body $($assignment | ConvertTo-Json -Depth 10) -StatusCodeVariable statusCode | Out-Null
    }
    catch{
      if(([REGEX]::Match($((($_ | ConvertFrom-Json).error.message | ConvertFrom-JSON).Message),"The MobileApp Assignment already exists")).Success){
        continue
      }
      else{
        throw $($_.Exception.Message)
      }
    }
  }
}
#EndRegion '.\Public\Copy-GraphIntuneAppAssignments.ps1' 32
#Region '.\Public\Disable-GraphUser.ps1' 0
function Disable-GraphUser{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true,ParameterSetName = 'userPrincipalName')][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Alias("id")][Parameter(Mandatory = $true, ParameterSetName = 'userid')][ValidateNotNullOrEmpty()][string]$userid
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userPrincipalName)"
  }
  if ($PSBoundParameters.ContainsKey("userid")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userid)"
  }
  $body = @{
    accountEnabled = $false
  }
  $headers = Get-GraphHeader
  Invoke-RestMethod -Method PATCH -Uri $endpoint -Headers $headers -body ($body | ConvertTo-Json) -StatusCodeVariable statusCode
}
#EndRegion '.\Public\Disable-GraphUser.ps1' 23
#Region '.\Public\Get-GraphAccessPackageAssignments.ps1' 0
function Get-GraphAccessPackageAssignments{
  [cmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$accessPackageId,
    [Parameter()][ValidateNotNullOrEmpty()][string]$groupid,
    [Parameter()][ValidateNotNullOrEmpty()][string]$groupname
  )  
  $endpoint = "identityGovernance/entitlementManagement/accessPackageAssignmentPolicies"
  if($id){
    $endpoint = "$($endpoint)?`$filter=id eq '$id'"
  }
  elseif($displayName){
    $endpoint = "$($endpoint)?`$filter=displayName eq '$displayName'"
  }
  elseif($accessPackageId){
    $endpoint = "$($endpoint)?`$filter=accessPackageId eq '$accessPackageId'"
  }
  # Create empty list
  $List = [System.Collections.Generic.List[PSCustomObject]]@()
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  try {
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    do {
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if ($results.value) {
        foreach ($item in $results.value) {
          if($groupid -or $groupName){
            $skipItem = $true
            if($item.requestorSettings.allowedRequestors.id -contains $groupID){
              $skipItem = $false
            }
            if($item.requestorSettings.allowedRequestors.description -contains $groupname){
              $skipItem = $false
            }
            if($item.requestApprovalSettings.approvalStages.primaryApprovers.id -contains $groupID){
              $skipItem = $false
            }
            if($item.requestApprovalSettings.approvalStages.primaryApprovers.description -contains $groupname){
              $skipItem = $false
            }                        
          }
          if($skipItem){continue}
          $List.add($item)
        }
      }
      $uri = $results."@odata.nextLink"
    }while ($null -ne $results."@odata.nextLink")
  }
  catch {
    throw "Unable to get Access Packages. $($_.Exception.Message)"
  }  
  return $List    
}
#EndRegion '.\Public\Get-GraphAccessPackageAssignments.ps1' 57
#Region '.\Public\Get-GraphAccessPackageCatalog.ps1' 0
function Get-GraphAccessPackageCatalog{
  [cmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName
  )
  $endpoint = "identityGovernance/entitlementManagement/accessPackageCatalogs"
  if($id){
    $endpoint = "$($endpoint)?`$filter=id eq '$id'"
  }
  elseif($displayName){
    $endpoint = "$($endpoint)?`$filter=displayName eq '$displayName'"
  }
  # Create empty list
  $List = [System.Collections.Generic.List[PSCustomObject]]@()
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  try {
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    do {
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if ($results.value) {
        foreach ($item in $results.value) {
          $List.add($item)
        }
      }
      $uri = $results."@odata.nextLink"
    }while ($null -ne $results."@odata.nextLink")
  }
  catch {
    throw "Unable to get Access Packages. $($_.Exception.Message)"
  }  
  return $List
}
#EndRegion '.\Public\Get-GraphAccessPackageCatalog.ps1' 35
#Region '.\Public\Get-GraphAccessPackages.ps1' 0
function Get-GraphAccessPackages {
  [cmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$id
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # URI Endpoint
  $endpoint = "identityGovernance/entitlementManagement/accessPackages"
  if ($id) {
    $endpoint = "$($endpoint)?`$filter=id eq '$($id)'"
  }
  elseif ($displayName) {
    $endpoint = "$($endpoint)?`$filter=displayName eq '$($displayName)'"
  }
  # Create empty list
  $List = [System.Collections.Generic.List[PSCustomObject]]@()
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  try {
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    do {
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if ($results.value) {
        foreach ($item in $results.value) {
          $List.add($item)
        }
      }
      $uri = $results."@odata.nextLink"
    }while ($null -ne $results."@odata.nextLink")
  }
  catch {
    throw "Unable to get Access Packages. $($_.Exception.Message)"
  }  
  return $List    
}
#EndRegion '.\Public\Get-GraphAccessPackages.ps1' 39
#Region '.\Public\Get-GraphAccessToken.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to use MSAL.PS to get an access token through an app registration, and then store in a global access token variable
  .PARAMETER clientID
  The client ID for the app registration used
  .PARAMETER clientSecret
  The secret used for the app registration
  .PARAMETER tenantID
  The tenant id for the app registration
#>

function Get-GraphAccessToken{
  [CmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$clientID,
    [Parameter()][ValidateNotNullOrEmpty()][string]$tenantID,
    [Parameter()][ValidateNotNullOrEmpty()][string]$clientSecret,
    [Parameter()][switch]$interactive,
    [Parameter()][ValidateNotNullOrEmpty()][PSCustomObject]$azToken
  )
  if($(Test-GraphAcessToken $script:graphAccessToken)){
    return $script:graphAccessToken
  }  
  Add-Type -Path "$($PSScriptRoot)\Microsoft.Identity.Client.dll" -ErrorAction SilentlyContinue | Out-Null
  [string[]]$scopes = @("https://graph.microsoft.com/.default")

  try{
    if($interactive.IsPresent){
      $clientApp = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($clientId).WithAuthority("https://login.microsoftonline.com/$tenantId").WithDefaultRedirectUri().Build()
      $authenticationResult = $clientApp.AcquireTokenInteractive($scopes).ExecuteAsync().GetAwaiter().GetResult()
    }
    elseif($clientSecret){
      $clientApp = [Microsoft.Identity.Client.ConfidentialClientApplicationBuilder]::Create($clientId).WithClientSecret($clientSecret).WithAuthority("https://login.microsoftonline.com/$tenantId").Build()
      $authenticationResult = $clientApp.AcquireTokenForClient($scopes).ExecuteAsync().GetAwaiter().GetResult()
    }
    elseif($azToken){
      $authenticationResult = $azToken.PSObject.Copy()
      $authenticationResult | Add-Member -MemberType AliasProperty -Name "AccessToken" -Value "Token" -Force

    }
    $script:graphAccessToken = $authenticationResult
    return $script:graphAccessToken
  }
  catch{
    throw "Unable to generate access token. Error message: $($_)"
  }
}
#EndRegion '.\Public\Get-GraphAccessToken.ps1' 47
#Region '.\Public\Get-GraphAPI.ps1' 0
function Get-GraphAPI {
  [CmdletBinding()]
  [OutputType([System.Collections.Generic.List[PSCustomObject]])]
  param(
    [Parameter(Mandatory = $true)][string]$endpoint,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$headers,
    [Parameter()][ValidateSet("Get", "Post", "Patch", "Delete", "Put")][string]$Method = "Get",
    [Parameter()][ValidateNotNullOrEmpty()]$body,
    [Parameter()][switch]$beta
  )
  $uri = "https://graph.microsoft.com/v1.0/"
  if ($PSBoundParameters.ContainsKey("beta")) { 
    $uri = $uri -replace "v1.0", "beta"
  }
  $uri = "$($uri)$($endpoint)"
  try {
    $Vars = @{
      Method             = $Method
      Uri                = $uri
      StatusCodeVariable = 'statusCode'
      headers            = $headers
    }
    if ($PSBoundParameters.ContainsKey("body")) { 
      $vars.add("body", ($body | ConvertTo-JSON))
    }
    Write-Verbose "Calling API endpoint: $($uri)" 
    $results = Invoke-RestMethod @Vars
  }
  catch {
    $ErrorMsg = $script:Error[0]
    return $ErrorMsg
  }
  return [PSCustomObject]@{
    StatusCode = $statusCode
    Results    = $results
  } 
}
#EndRegion '.\Public\Get-GraphAPI.ps1' 38
#Region '.\Public\Get-GraphApplications.ps1' 0
function Get-GraphApplications{
  [CmdletBinding(DefaultParameterSetName = "All")]
  param(
    [Parameter(ParameterSetName = 'id')][validatenotnullorempty()][string]$id,
    [Parameter(ParameterSetName = 'appid')][validatenotnullorempty()][string]$appId,
    [Parameter(ParameterSetName = 'displayName')][validatenotnullorempty()][string]$displayName,
    [Parameter(ParameterSetName = 'filter')][ValidateNotNullOrEmpty()][string]$filter,
    [Parameter()][switch]$all,
    [Parameter()][ValidateNotNullOrEmpty()][string]$fields
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Get Graph Header
  $headers = Get-GraphHeader  
  $endpoint = "applications"
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()  
  if($PSBoundParameters.ContainsKey("id")) {$uriparts.add("`$filter=id -eq '$($id)'")}
  if($PSBoundParameters.ContainsKey("appId")){$uriparts.add("`$filter=appId -eq '$($appId)'")}
  if ($PSBoundParameters.ContainsKey("displayName")) {$uriparts.add("`$filter=displayName -eq '$($displayName)'")}
  if ($PSBoundParameters.ContainsKey("filter")) {$uriparts.add("`$filter=$($filter)")}
  if ($PSBoundParameters.ContainsKey("fields")) {$uriparts.add("`$select=$($fields)")}
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?$($uriparts -join "&")" 
  try {
    # Create empty list
    $applications = [System.Collections.Generic.List[PSCustomObject]]@()    
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $applications.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($applications.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "applications.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink" -and $all.IsPresent)
  }
  catch {
    throw "Unable to get users. $($_.Exception.Message)"
  } 
  if($applications.count -eq 0){
    return $results
  }
  else{
    # Return the group list if it exists
    return $applications
  }
}

<#
  # Base Endpoint
   
 
  $filters = [System.Collections.Generic.List[PSCustomObject]]@()
  if($PSBoundParameters.ContainsKey("displayName")){
    $filters.Add("=displayName -eq '$($displayName)'") | Out-Null
  }
  if($PSBoundParameters.ContainsKey("filter")){
    $filters.Add($filter) | Out-Null
  }
  $filter = $filters -join " and "
  $endpoint = "$($endpoint)?$($uriparts -join "&")"
#>

#EndRegion '.\Public\Get-GraphApplications.ps1' 68
#Region '.\Public\Get-GraphAutopilotInformation.ps1' 0
function Get-GraphAutopilotInformation {
  [CmdletBinding()]
  param(
    [parameter()][ValidateNotNullOrEmpty()][string]$SerialNumber,
    [parameter()][ValidateNotNullOrEmpty()][string]$groupTag,
    [parameter()][ValidateNotNullOrEmpty()][string]$manufacturer,
    [parameter()][ValidateNotNullOrEmpty()][string]$model,
    [parameter()][ValidateNotNullOrEmpty()][string]$azureAdDeviceId
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  $endpoint = "deviceManagement/windowsAutopilotDeviceIdentities"
  # Create empty list
  $filters = [System.Collections.Generic.List[PSCustomObject]]@()
  if($groupTag){
    $filters.Add("contains(groupTag,'$($groupTag)')") | Out-Null
  }
  if($SerialNumber){
    $filters.Add("contains(SerialNumber,'$($SerialNumber)')") | Out-Null
  }  
  if($manufacturer){
    $filters.Add("contains(manufacturer,'$($manufacturer)')") | Out-Null
  }   
  if($model){
    $filters.Add("contains(model,'$($model)')") | Out-Null
  }   
  if($userPrincipalName){
    $filters.Add("contains(userPrincipalName,'$($userPrincipalName)')") | Out-Null
  }  
  if($azureAdDeviceId){
    $filters.Add("contains(azureAdDeviceId,'$($azureAdDeviceId)')") | Out-Null
  }  
  # Create query string for the filter
  $filterList = $filters -join " and "  
  if($filterList){
    $endpoint = "$($endpoint)?`$filter=$($filterList)"
  }  
  # Create empty list
  $deviceList = [System.Collections.Generic.List[PSCustomObject]]@() 
  # Get Graph Headers for Call
  $headers = Get-GraphHeader 
  # Get Autopilot Devices
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  do {
    # Execute call against graph
    $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode 
    foreach($item in $results.value){
      $deviceList.Add($item) | Out-Null
    }
    # Set the URI to the nextlink if it exists
    $uri = $results."@odata.nextLink"     
  }while ($null -ne $results."@odata.nextLink")
  return $deviceList
}
#EndRegion '.\Public\Get-GraphAutopilotInformation.ps1' 56
#Region '.\Public\Get-GraphDevice.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to get devices from Azure ID
#>

function Get-GraphDevice{
  [CmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string[]]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string[]]$deviceId,
    [Parameter()][ValidateNotNullOrEmpty()][bool]$accountEnabled,
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$fields
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # Create empty list
  $filters =  [System.Collections.Generic.List[PSCustomObject]]@()  
  if($displayName){
    $filters.Add("displayName eq '$($displayName)'") | Out-Null
  }
  if($accountEnabled){
    $filters.Add("accountEnabled eq '$($accountEnabled)'") | Out-Null
  }
  if($deviceId.count -eq 1){  
    $filters.Add("deviceId eq '$($deviceId)'") | Out-Null
  }
  $batch = $false
  # General endpoint
  $endpoint = "devices"
  if($id.count -eq 1){
    $endpoint = "$($endpoint)/$($id)"
  }
  elseif($id.count -gt 1 -or $deviceId.count -gt 1){
    $batch = $true
  }
  # Create query string for the filter
  $filterList = $filters -join " and "
  # Create empty list
  $deviceList =  [System.Collections.Generic.List[PSCustomObject]]@() 
  # Get Graph Headers for Call
  $headers = Get-GraphHeader       
  # If ID and deviceID are not an array
  if(-not $batch){
    # Setup endpoint based on if filter or fields are passed
    if($filterList){
      $endpoint = "$($endpoint)?`$filter=$($filterList)"
    }
    if($filterList -and $fields){
      $endpoint = "$($endpoint)&`$select=$($fields)"
    }
    elseif($fields){
      $endpoint = "$($endpoint)?`$select=$($fields)"
    }    
    # Try to call graph API and get results back
    try{
      $uri = "https://graph.microsoft.com/beta/$($endpoint)"
      do{
        $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
        if($results.value){
          foreach($item in $results.value){
            $deviceList.Add($item) | Out-Null
          }
        }
        else{
          $deviceList.Add($results) | Out-Null
        }
        $uri = $results."@odata.nextLink"
      }while($null -ne $results."@odata.nextLink")      
    }
    catch{
      throw "Unable to get devices. $($_.Exception.Message)"
    } 
    return $deviceList   
  }
  # If a batch job because id or device id is an array
  else{
    $objid = 1
    $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
    $batches = [System.Collections.Generic.List[PSCustomObject]]@()
    # if trying to return multiple ids
    if($id.count -gt 1){
      foreach($device in $id){
        if($objid -lt 21){
          if($fields){
            $uri = "$($endpoint)/$($device)?`$select=$($fields)"
          }
          else{
            $uri = "$($endpoint)/$($device)"
          }
          $obj = [PSCustomObject]@{
            "id" = $objid
            "method" = "GET"
            "url" = $uri
          }
          $batchObj.Add($obj) | Out-Null
          $objid++          
        }
        if($objId -eq 21){
          $batches.Add($batchObj) | Out-Null
          $batchObj = $null
          $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
          $objid = 1 
        }        
      }
      $batches.Add($batchObj) | Out-Null
    }
    # if trying to return multiple deviceids
    elseif($deviceId.Count -gt 1){
      foreach($device in $deviceId){
        if($objid -lt 21){
          if($fields){
            $uri = "$($endpoint)?`$filter=deviceId eq '$($device)'&`$select=$($fields)"
          }
          else{
            $uri = "$($endpoint)?`$filter=deviceId eq '$($device)'"
          }
          $obj = [PSCustomObject]@{
            "id" = $objid
            "method" = "GET"
            "url" = $uri
          }
          $batchObj.Add($obj) | Out-Null
          $objid++          
        }
        if($objId -eq 21){
          $batches.Add($batchObj) | Out-Null
          $batchObj = $null
          $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
          $objid = 1 
        }        
      }
      $batches.Add($batchObj) | Out-Null
    }
    for($x = 0; $x -lt $batches.count; $x++){
      if($batches[$x].count -gt 0){
        $json = [PSCustomObject]@{
          "requests" = $batches[$x] 
        } | ConvertTo-JSON    
        $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json
        foreach($item in $results.responses.body){
          if($item.value){
            $deviceList.Add($item.value) | Out-Null
          }
          else{
            $deviceList.Add($item) | Out-Null
          }

        }
      }    
    }
    return $deviceList
  }
}
#EndRegion '.\Public\Get-GraphDevice.ps1' 155
#Region '.\Public\Get-GraphGroup.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to query graph for Entra ID groups
  .PARAMETER groupName
  If want to find based on group name
  .PARAMETER groupId
  If want to lookup by group id
  .PARAMETER All
  If want to return all groups
#>

function Get-GraphGroup{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true,ParameterSetName = 'groupName')][ValidateNotNullOrEmpty()][string]$groupName,
    [Parameter(Mandatory = $true, ParameterSetName = 'groupId')][ValidateNotNullOrEmpty()][string]$groupId,
    [Parameter(Mandatory = $true, ParameterSetName = 'All')][switch]$All
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Create empty list
  $groupList =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Build the headers we will use to get groups
  $headers = Get-GraphHeader
  # Base URI for resource call
  $uri = "https://graph.microsoft.com/beta/groups"
  if($groupName){
    # Filter based on group name is required
    $uri = "$($uri)?`$filter=displayName eq '$($groupName)'"
  }
  elseif($groupId){
    # Filter based on group ID
    $uri = "$($uri)/$($groupId)"
  }
  try{
    # Loop until nextlink is null
    do{
      # Execute call against graph
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      # Add results to a list variable
      foreach($item in $results.value){
        $groupList.Add($item) | Out-Null
      }
      # Set the URI to the nextlink if it exists
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
    # If there is only one result, return that
    if($groupList.count -eq 0){
      return $results
    }
    else{
      # Return the group list if it exists
      return $groupList
    }
  }
  catch{
    throw "Unable to get groups. $($_.Exception.Message)"
  }
}
#EndRegion '.\Public\Get-GraphGroup.ps1' 61
#Region '.\Public\Get-GraphGroupMembers.ps1' 0
#https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-beta&tabs=http
function Get-GraphGroupMembers{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true,ParameterSetName = 'groupName')][ValidateNotNullOrEmpty()][string]$groupName,
    [Parameter(Mandatory = $true, ParameterSetName = 'groupId')][ValidateNotNullOrEmpty()][string]$groupId,
    [Parameter()][switch]$Recurse
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Get the Group ID if Group Name was Sent
  if($groupName){
    $group = Get-GraphGroup -groupName $groupName
    $groupId = $group.id
  }
  # Create empty list
  $groupMemberList =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Create List for recurse if needed
  $groupList =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Build the headers we will use to get groups
  $headers = Get-GraphHeader
  # Deterime if we just want members of transitive members
  if($Recurse){
    $uri = "https://graph.microsoft.com/beta/groups/$($groupId)/transitiveMembers"
  }
  else{
    $uri = "https://graph.microsoft.com/beta/groups/$($groupId)/members"
  }
  try{
    # Loop until nextlink is null
    do{
      # Execute call against graph
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      # Add results to a list variable
      foreach($item in $results.value){
        $groupMemberList.Add($item)
      }
      # Set the URI to the nextlink if it exists
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
    return $groupMemberList
  }
  catch{
    throw "Unable to get group members. $($_.Exception.Message)"
  }
}
#EndRegion '.\Public\Get-GraphGroupMembers.ps1' 49
#Region '.\Public\Get-GraphHeader.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to format the graph header for the REST api calls
  .PARAMETER ConsistencyLevel
  This field will add the ConsistencyLevel variable to eventual
#>

function Get-GraphHeader{
  [CmdletBinding()]
  param(
    [Parameter()][switch]$ConsistencyLevel
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Base header variables
  $headerVars = @{
    Authorization = "Bearer $($script:graphAccessToken.AccessToken)"
    "Content-Type" = "application/json"
  }
  # If flagged to include the Consitency Level header
  if($ConsistencyLevel.IsPresent){
    $headerVars.Add("ConsistencyLevel","eventual")
  }
  return $headerVars
}
#EndRegion '.\Public\Get-GraphHeader.ps1' 26
#Region '.\Public\Get-GraphIntuneAPNCertificate.ps1' 0
function Get-GraphIntuneAPNCertificate{
  [CmdletBinding()]
  param()
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # URI Endpoint
  $endpoint = "deviceManagement/applePushNotificationCertificate"
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  # Invoke Rest API
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
  # return results
  return $results
}
#EndRegion '.\Public\Get-GraphIntuneAPNCertificate.ps1' 17
#Region '.\Public\Get-GraphIntuneApp.ps1' 0
function Get-GraphIntuneApp{
  [CmdletBinding(DefaultParameterSetName = 'All')]
  param(
    [Parameter(Mandatory = $true,ParameterSetName = 'id')][ValidateNotNullOrEmpty()][string]$id,
    [Parameter(Mandatory = $true, ParameterSetName = 'displayName')][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("microsoft.graph.androidManagedStoreApp","microsoft.graph.iosStoreApp","microsoft.graph.iosVppApp","microsoft.graph.macOSLobApp","microsoft.graph.macOSMicrosoftEdgeApp","microsoft.graph.macOSOfficeSuiteApp","microsoft.graph.macOSPkgApp","microsoft.graph.macOsVppApp","microsoft.graph.managedAndroidStoreApp","microsoft.graph.managedIOSStoreApp","microsoft.graph.officeSuiteApp","microsoft.graph.webApp","microsoft.graph.win32LobApp","microsoft.graph.winGetApp")]
      [string]$type,
    [Parameter()][ValidateNotNullOrEmpty()][string]$fields
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  
  
  # URI Endpoint
  $endpoint = "deviceAppManagement/mobileApps"
  # Build filters for URI
  $filters =  [System.Collections.Generic.List[PSCustomObject]]@()
  if($id){
    $filters.Add("id eq '$($id)'") | Out-Null
  }
  if($displayName){
    $filters.Add("displayName eq '$($displayName)'") | Out-Null
  }  
  if($type){
    $filters.Add("(isof('$($type)'))") | Out-Null
  }   
  # Create query string for the filter
  $filterList = $filters -join " and "
  if($filterList){
    $endpoint = "$($endpoint)?`$filter=$($filterList)"
  }
  if($filterList -and $fields){
    $endpoint = "$($endpoint)&`$select=$($fields)"
  }
  elseif($fields){
    $endpoint = "$($endpoint)?`$select=$($fields)"
  }
  # Create empty list
  $applicationList =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  try{
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    do{
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if($results.value){
        foreach($item in $results.value){
          $applicationList.add($item)
        }
      }
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
  }
  catch{
    throw "Unable to get devices. $($_.Exception.Message)"
  }  
  return $applicationList
}
#EndRegion '.\Public\Get-GraphIntuneApp.ps1' 60
#Region '.\Public\Get-GraphIntuneAppAssignment.ps1' 0
function Get-GraphIntuneAppAssignment{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][PSCustomObject]$applicationid
  )
  $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)/assignments"
  $headers = Get-GraphHeader
  $results = Invoke-RestMethod -Method "GET" -Uri $endpoint -Headers $headers
  return $results.value
}
#EndRegion '.\Public\Get-GraphIntuneAppAssignment.ps1' 11
#Region '.\Public\Get-GraphIntuneDEPCertificate.ps1' 0
function Get-GraphIntuneDEPCertificate{
  [CmdletBinding()]
  param()
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # URI Endpoint
  $endpoint = "deviceManagement/depOnboardingSettings"
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  # Invoke Rest API
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
  # return results
  return $results.Value  
}
#EndRegion '.\Public\Get-GraphIntuneDEPCertificate.ps1' 17
#Region '.\Public\Get-GraphIntuneEnrollmentStatusPage.ps1' 0
function Get-GraphIntuneEnrollmentStatusPage{
  [CmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # URI Endpoint
  $endpoint = "deviceManagement/deviceEnrollmentConfigurations"
  if($id){
    $endpoint = "$($endpoint)/$($id)"
  }
  if($displayName){
    $endpoint = "$($endpoint)?`$filter=displayName eq '$($displayName)'"
  }
  # Create empty list
  $esplist =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  try{
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    do{
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if($results.value){
        foreach($item in $results.value){
          $esplist.add($item)
        }
      }
      else{
        $esplist.add($results)
      }
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
  }
  catch{
    throw "Unable to get devices. $($_.Exception.Message)"
  }
  return $esplist  
}
#EndRegion '.\Public\Get-GraphIntuneEnrollmentStatusPage.ps1' 42
#Region '.\Public\Get-GraphIntuneFilters.ps1' 0
function Get-GraphIntuneFilters{
  [CmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][string]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string]$displayName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$platform
  )
  # Construct array list to build the dynamic filter list
  $FilterList = [System.Collections.Generic.List[PSCustomObject]]@()
  if($id){
    $FilterList.Add("`$PSItem.id -eq '$($id)'") | Out-Null
  }
  if($displayName){
    $FilterList.Add("`$PSItem.displayName -eq '$($displayName)'") | Out-Null
  }
  if($platform){
    $FilterList.Add("`$PSItem.platform -eq '$($platform)'") | Out-Null
  }
  # Construct script block from filter list array
  $FilterExpression = [scriptblock]::Create(($FilterList -join " -and ")) 
  # Create empty list
  $filters =  [System.Collections.Generic.List[PSCustomObject]]@()
  # Build the headers we will use to get groups
  $headers = Get-GraphHeader  
  # Endpoint for the API
  $uri = "https://graph.microsoft.com/beta/deviceManagement/assignmentFilters"
  try{
    # Loop until nextlink is null
    do{
      # Execute call against graph
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      # Add results to a list variable
      foreach($item in $results.value){
        $filters.Add($item)
      }
      # Set the URI to the nextlink if it exists
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
    if($FilterList.Count -gt 0){
      return $filters | Where-Object -FilterScript $FilterExpression
    }
    return $filters
  }
  catch{
    throw "Unable to get group members. $($_.Exception.Message)"
  }  
}
#EndRegion '.\Public\Get-GraphIntuneFilters.ps1' 48
#Region '.\Public\Get-GraphIntuneVPPCertificate.ps1' 0
function Get-GraphIntuneVPPCertificate{
  [CmdletBinding()]
  param()
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # URI Endpoint
  $endpoint = "deviceAppManagement/vppTokens"
  # Get Graph Headers for Call
  $headers = Get-GraphHeader
  # Invoke Rest API
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
  # return results
  return $results.Value
}
#EndRegion '.\Public\Get-GraphIntuneVPPCertificate.ps1' 17
#Region '.\Public\Get-GraphMail.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to read email from a specific mailbox
  .PARAMETER mailbox
  The email address of the account that we are reading from
  .PARAMETER folder
  The ID of the folder that we want to read from, if it is not the whole mailbox
  .PARAMETER unread
  If we want to return only unread email
#>

function Get-GraphMail{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$mailbox,
    [Parameter()][ValidateNotNullOrEmpty()][string]$folderid,
    [Parameter(ParameterSetName = "unread")][switch]$unread,
    [Parameter(ParameterSetName = "filter")][string]$filter,
    [Parameter()][switch]$all
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Get Graph Header
  $headers = Get-GraphHeader   
  $endpoint = "users/$($mailbox)"
  if ($PSBoundParameters.ContainsKey("folderid")) {
    $endpoint = "$($endpoint)/mailFolders/$($folderid)"
  }
  $endpoint = "$($endpoint)/messages"
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()
  if ($PSBoundParameters.ContainsKey("unread")) {$uriparts.add("`$filter=isRead eq false")}
  if ($PSBoundParameters.ContainsKey("filter")) {$uriparts.add("`$filter=$($filter)")}
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?$($uriparts -join "&")"    
  try {
    # Create empty list
    $maillist = [System.Collections.Generic.List[PSCustomObject]]@()    
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $maillist.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($maillist.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "users.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink" -and $all.IsPresent)
  }
  catch {
    throw "Unable to get users. $($_.Exception.Message)"
  } 
  if($maillist.count -eq 0){
    return $results
  }
  else{
    # Return the group list if it exists
    return $maillist
  }
}
#EndRegion '.\Public\Get-GraphMail.ps1' 64
#Region '.\Public\Get-GraphMailAttachment.ps1' 0
function Get-GraphMailAttachment{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$mailbox,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$messageid
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Get Graph Header
  $headers = Get-GraphHeader 
  $endpoint = "users/$($mailbox)/messages/$($messageid)/attachments"
  $results = Get-GraphAPI -endpoint $endpoint -headers $headers -beta -Verbose:$VerbosePreference
  return $results.results.value
}
#EndRegion '.\Public\Get-GraphMailAttachment.ps1' 17
#Region '.\Public\Get-GraphMailAttachmentContent.ps1' 0
function Get-GraphMailAttachmentContent{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$mailbox,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$messageid,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$attachmentid,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$filename
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  $headers = Get-GraphHeader  
  Invoke-RestMethod -method "GET" -uri "https://graph.microsoft.com/beta/users/$($mailbox)/messages/$($messageid)/attachments/$($attachmentid)/`$value" -Headers $headers -OutFile $filename
}
#EndRegion '.\Public\Get-GraphMailAttachmentContent.ps1' 15
#Region '.\Public\Get-GraphMailFolder.ps1' 0
function Get-GraphMailFolder {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$mailbox,
    [Parameter()][ValidateNotNullOrEmpty()][string]$foldername,
    [Parameter()][switch]$includeHiddenFolders,
    [Parameter()][switch]$all
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Get Graph Header
  $headers = Get-GraphHeader  
  $endpoint = "users/$($mailbox)/mailFolders"
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()
  if ($PSBoundParameters.ContainsKey("foldername")) { $uriparts.add("`$filter=displayName eq '$($foldername)'") }
  if ($PSBoundParameters.ContainsKey("includeHiddenFolders")) { $uriparts.add("includeHiddenFolders=true") }
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?$($uriparts -join "&")"  
  try {
    # Create empty list
    $mailfolders = [System.Collections.Generic.List[PSCustomObject]]@()    
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $mailfolders.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($mailfolders.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "users.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink" -and $all.IsPresent)
  }
  catch {
    throw "Unable to get users. $($_.Exception.Message)"
  } 
  return $mailfolders
}
#EndRegion '.\Public\Get-GraphMailFolder.ps1' 43
#Region '.\Public\Get-GraphMailRules.ps1' 0
function Get-GraphMailRules {
  [CmdletBinding()]
  [OutputType([System.Collections.Generic.List[PSCustomObject]])]
  param(
    [Parameter(Mandatory = $true, ParameterSetName = 'userPrincipalName')][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Alias("id")][Parameter(Mandatory = $true, ParameterSetName = 'userid')][ValidateNotNullOrEmpty()][string]$userid
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userPrincipalName)/mailFolders/inbox/messageRules"
  }
  if ($PSBoundParameters.ContainsKey("userid")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userid)/mailFolders/inbox/messageRules"
  }   
  $headers = Get-GraphHeader
  $results = Invoke-RestMethod -Method Get -Uri $endpoint -Headers $headers -StatusCodeVariable statusCode
  $results.value
}
#EndRegion '.\Public\Get-GraphMailRules.ps1' 22
#Region '.\Public\Get-GraphManagedDevice.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to get managed devices (intune) from the graph endpoints
#>

function Get-GraphManagedDevice{
  [CmdletBinding()]
  param(
    [Parameter()][ValidateNotNullOrEmpty()][datetime]$lastSyncBefore,
    [Parameter()][ValidateNotNullOrEmpty()][datetime]$lastSyncAfter,
    [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("Windows","Android","macOS","iOS")][string]$operatingSystem,
    [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("compliant","noncompliant","unknown")][string]$complianceState,
    [Parameter()][ValidateNotNullOrEmpty()][string]$OSVersion,
    [Parameter()][ValidateNotNullOrEmpty()][string]$OSVersionStartsWith,
    [Parameter()][ValidateNotNullOrEmpty()][string]$id,
    [Parameter()][ValidateNotNullOrEmpty()][string]$azureADDeviceId,
    [Parameter()][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$model,
    [Parameter()][ValidateNotNullOrEmpty()][string]$manufacturer,
    [Parameter()][ValidateNotNullOrEmpty()][string]$serialNumber,
    [Parameter()][ValidateNotNullOrEmpty()][ValidateSet("disabled","enabled")][string]$lostModeState,
    [Parameter()][ValidateNotNullOrEmpty()][string]$minimumOSVersion,
    [Parameter()][ValidateNotNullOrEmpty()][string]$maximumOSVersion,
    [Parameter()][ValidateNotNullOrEmpty()][bool]$isEncrypted,
    [Parameter()][ValidateNotNullOrEmpty()][string]$fields,
    [Parameter()][switch]$batch
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  # Create Filters for the URI
  # Create empty list
  $filters =  [System.Collections.Generic.List[PSCustomObject]]@()  
  # Build Filters
  if($lastSyncBefore){
    $filters.Add("lastSyncDateTime le $($lastSyncBefore.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null
  }
  if($lastSyncAfter){
    $filters.Add("lastSyncDateTime ge $($lastSyncAfter.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null
  }  
  if($operatingSystem){
    $filters.Add("operatingSystem eq '$($operatingSystem)'") | Out-Null
  }   
  if($complianceState){
    $filters.Add("complianceState eq '$($complianceState)'") | Out-Null
  }     
  if($OSVersion){
    $filters.Add("OSVersion eq '$($OSVersion)'") | Out-Null
  }    
  if($OSVersionStartsWith){
    $filters.Add("startsWith(OSVersion,'$($OSVersionStartsWith)')") | Out-Null
  }  
  if($azureADDeviceId){
    $filters.Add("azureADDeviceId eq '$($azureADDeviceId)'") | Out-Null
  }   
  if($userPrincipalName){
    $filters.Add("userPrincipalName eq '$($userPrincipalName)'") | Out-Null
  } 
  if($model){
    $filters.Add("model eq '$($model)'") | Out-Null
  }          
  if($manufacturer){
    $filters.Add("manufacturer eq '$($manufacturer)'") | Out-Null
  }    
  if($serialNumber){
    $filters.Add("serialNumber eq '$($serialNumber)'") | Out-Null
  }   
  # Create query string for the filter
  $filterList = $filters -join " and "
  # URI Endpoint
  $endpoint = "deviceManagement/managedDevices"
  if($id){
    $uri = "$($endpoint)/$($id)"
  } 
  else{
    $uri = "$($endpoint)"    
  }  
  if($filterList){
    $uri = "$($uri)?`$filter=$($filterList)"
  }
  if(!$batch){
    if($fields -ne ""){
      if($filters.count -gt 0){
        $uri = "$($uri)&`$select=$($fields)"
      }
      else{
        $uri = "$($uri)?`$select=$($fields)"
      }
    }
  }
  else{
    if($fields -ne ""){
      if($filters.count -gt 0){
        $uri = "$($uri)&`$select=id"
      }
      else{
        $uri = "$($uri)?`$select=id"
      }    
    }
  }
  # Create empty list
  $deviceList =  [System.Collections.Generic.List[PSCustomObject]]@()  
  # Create empty list
  $idlist =  [System.Collections.Generic.List[PSCustomObject]]@()    
  # Get Graph Headers for Call
  $headers = Get-GraphHeader  
  try{
    $uri = "https://graph.microsoft.com/beta/$($uri)"
    do{
      $results = Invoke-RestMethod -Method Get -Uri $uri -Headers $headers -StatusCodeVariable statusCode
      if($results.value){
        foreach($item in $results.value){
          if(!$batch){$deviceList.Add($item) | Out-Null}
          else{$idlist.Add($item) | Out-Null}
        }
      }
      else{
        if(!$batch){$deviceList.Add($item) | Out-Null}
        else{$idlist.Add($item) | Out-Nul}
      }
      $uri = $results."@odata.nextLink"
    }while($null -ne $results."@odata.nextLink")
  }
  catch{
    throw "Unable to get devices. $($_.Exception.Message)"
  }
  if(!$batch)
  {
    return $deviceList
  }
  $objid = 1
  $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
  $batches = [System.Collections.Generic.List[PSCustomObject]]@()
  foreach($device in $idlist){
    if($objid -lt 21){
      $url = "deviceManagement/managedDevices/$($device.id)"
      if($fields -ne ""){
        $url = "$($url)?`$select=$($fields)"
      }
      $obj = [PSCustomObject]@{
        "id" = $objid
        "method" = "GET"
        "url" = $url
      }
      $batchObj.Add($obj) | Out-Null
      $objid++
    }
    if($objId -eq 21){
      $batches.Add($batchObj) | Out-Null
      $batchObj = $null
      $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
      $objid = 1 
    }
  }  
  $batches.Add($batchObj) | Out-Null
  for($x = 0; $x -lt $batches.count; $x++){
    if($batches[$x].count -gt 0){
      $json = [PSCustomObject]@{
        "requests" = $batches[$x] 
      } | ConvertTo-JSON    
      $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json
      foreach($item in $results.responses.body){
        $deviceList.Add($item) | Out-Null
      }   
    } 
  }
  return $deviceList
}
#EndRegion '.\Public\Get-GraphManagedDevice.ps1' 168
#Region '.\Public\Get-GraphServicePrincipals.ps1' 0
function Get-GraphServicePrincipals{
  [CmdletBinding(DefaultParameterSetName = "All")]
  param(
    [Parameter(ParameterSetName = 'id')][validatenotnullorempty()][string]$id,
    [Parameter(ParameterSetName = 'appid')][validatenotnullorempty()][string]$appId,
    [Parameter(ParameterSetName = 'displayName')][validatenotnullorempty()][string]$displayName,
    [Parameter(ParameterSetName = 'filter')][ValidateNotNullOrEmpty()][string]$filter,
    [Parameter()][switch]$all,
    [Parameter()][ValidateNotNullOrEmpty()][string]$fields
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Get Graph Header
  $headers = Get-GraphHeader  
  $endpoint = "servicePrincipals"
  if($PSBoundParameters.ContainsKey("id")){
    $endpoint = "$($endpoint)/$($id)"
  }
  if($PSBoundParameters.ContainsKey("appId")){
    $endpoint = "$($endpoint)(appid=$($id))"
  }
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()
  if ($PSBoundParameters.ContainsKey("displayName")) {$uriparts.add("`$filter=displayName -eq '$($displayName)'")}
  if ($PSBoundParameters.ContainsKey("filter")) {$uriparts.add("`$filter=$($filter)")}
  if ($PSBoundParameters.ContainsKey("fields")) {$uriparts.add("`$select=$($fields)")}
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?$($uriparts -join "&")" 
  try {
    # Create empty list
    $servicePrincipals = [System.Collections.Generic.List[PSCustomObject]]@()    
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $servicePrincipals.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($servicePrincipals.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "servicePrincipals.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink" -and $all.IsPresent)
  }
  catch {
    throw "Unable to get users. $($_.Exception.Message)"
  } 
  if($servicePrincipals.count -eq 0){
    return $results
  }
  else{
    # Return the group list if it exists
    return $servicePrincipals
  }
}

<#
  # Base Endpoint
   
 
  $filters = [System.Collections.Generic.List[PSCustomObject]]@()
  if($PSBoundParameters.ContainsKey("displayName")){
    $filters.Add("=displayName -eq '$($displayName)'") | Out-Null
  }
  if($PSBoundParameters.ContainsKey("filter")){
    $filters.Add($filter) | Out-Null
  }
  $filter = $filters -join " and "
  $endpoint = "$($endpoint)?$($uriparts -join "&")"
#>

#EndRegion '.\Public\Get-GraphServicePrincipals.ps1' 72
#Region '.\Public\Get-GraphSignInAuditLogs.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to query the sign in logs for the users in the entra id tenant
  .PARAMETER userDisplayName
  The list of user display names that we should be looking for
  .PARAMETER userPrincipalName
  The list of user principal names that we should be looking for
  .PARAMETER userId
  The lsit of user ids that we should be looking for
  .PARAMETER appDisplayName
  The name of the application that we attempted to sign into
  .PARAMETER ipAddress
  The list of ipaddresses that we should be looking for
  .PARAMETER afterDateTime
  Sign ins after this date
#>

function Get-GraphSignInAuditLogs{
  [CmdletBinding()]
  param(
    [Parameter()][string[]]$userDisplayName,
    [Parameter()][string[]]$userPrincipalName,
    [Parameter()][string[]]$userId,
    [Parameter()][string[]]$appDisplayName,
    [Parameter()][string[]]$ipAddress,
    [Parameter()][datetime]$afterDateTime
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # URI Endpoint
  $endpoint = "auditLogs/signIns"
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()
  if ($PSBoundParameters.ContainsKey("userDisplayName")) {
    $list =  [System.Collections.Generic.List[String]]@()
    foreach($item in $userDisplayName){
      $list.Add("userDisplayName eq '$($item)'") | Out-Null
    }
    $uriparts.Add("($($list -join " or "))") | Out-Null    
  }
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) {
    $list =  [System.Collections.Generic.List[String]]@()
    foreach($item in $userPrincipalName){
      $list.Add("userPrincipalName eq '$($item)'") | Out-Null
    }
    $uriparts.Add("($($list -join " or "))") | Out-Null
  }  
  if ($PSBoundParameters.ContainsKey("userId")) {
    $list =  [System.Collections.Generic.List[String]]@()
    foreach($item in $userId){
      $list.Add("userId eq '$($item)'") | Out-Null
    }
    $uriparts.Add("($($list -join " or "))") | Out-Null
  }  
  if ($PSBoundParameters.ContainsKey("ipAddress")) {
    $list =  [System.Collections.Generic.List[String]]@()
    foreach($item in $ipAddress){
      $list.Add("ipAddress eq '$($item)'") | Out-Null
    }
    $uriparts.Add("($($list -join " or "))") | Out-Null
  }   
  if ($PSBoundParameters.ContainsKey("afterDateTime")) {
    $uriparts.Add("createdDateTime ge $($afterDateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))") | Out-Null
  }  
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?`$filter=$($uriparts -join " and ")"
  # Get Graph Headers for Call
  $headers = Get-GraphHeader 
  try {
    $signinList =  [System.Collections.Generic.List[PSCustomObject]]@()
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $signinList.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($signinList.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "auditLogs/signIns.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink")     
  }
  catch {
    throw $_
  } 
  return $signinList
}
#EndRegion '.\Public\Get-GraphSignInAuditLogs.ps1' 90
#Region '.\Public\Get-GraphUser.ps1' 0
function Get-GraphUser {
  [CmdletBinding(DefaultParameterSetName = "All")]
  [OutputType([System.Collections.Generic.List[PSCustomObject]])]
  param(
    [Parameter(Mandatory = $true, ParameterSetName = 'userPrincipalName')][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Parameter(Mandatory = $true, ParameterSetName = 'userid')][ValidateNotNullOrEmpty()][string]$userid,
    [Parameter()][switch]$All,
    [Parameter()][switch]$ConsistencyLevel,
    [Parameter()][switch]$Count,
    [Parameter()][ValidateNotNullOrEmpty()][string]$filter,
    [Parameter()][ValidateNotNullOrEmpty()][string]$select
  )  
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  # Build the headers we will use to get groups
  $ConsistencyLevelHeader = @{}
  if ($PSBoundParameters.ContainsKey("ConsistencyLevel")) {
    $ConsistencyLevelHeader.Add("ConsistencyLevel", $true) | Out-Null
  }
  $headers = Get-GraphHeader @ConsistencyLevelHeader
  # Create empty list
  $userList = [System.Collections.Generic.List[PSCustomObject]]@()
  # Base URI for resource call
  $endpoint = "users"
  $uriparts = [System.Collections.Generic.List[PSCustomObject]]@()
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) {
    # Filter based on group name is required
    $endpoint = "$($endpoint)/$($userPrincipalName)"    
  }
  elseif ($PSBoundParameters.ContainsKey("userid")) {
    $endpoint = "$($endpoint)/$($userid)"
  }
  if ($PSBoundParameters.ContainsKey("filter")) { $uriparts.add("`$filter=$($filter)") }
  if ($PSBoundParameters.ContainsKey("select")) { $uriparts.add("`$select=$($select)") }
  if ($PSBoundParameters.ContainsKey("count")) { $uriparts.add("`$count=true") }
  # Generate the final API endppoint URI
  $endpoint = "$($endpoint)?$($uriparts -join "&")"
  try {
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $userList.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($userList.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "users.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink" -and $all.IsPresent)
  }
  catch {
    throw "Unable to get users. $($_.Exception.Message)"
  } 
  # If there is only one result, return that
  if ($userList.count -eq 0) {
    return $results.Results
  }
  else {
    # Return the group list if it exists
    return $userList
  }
}
#EndRegion '.\Public\Get-GraphUser.ps1' 67
#Region '.\Public\Get-GraphUserGroups.ps1' 0

function Get-GraphUserGroups {
  [CmdletBinding()]
  [OutputType([System.Collections.Generic.List[PSObject]])]
  param(
    [Alias("userPrincipalName")][Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$userid,
    [Parameter(Mandatory = $true, ParameterSetName = 'directMembership')][switch]$directMembership,
    [Parameter(Mandatory = $true, ParameterSetName = 'transitiveMemberOf')][switch]$transitiveMemberOf
  )
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Build the endpoint
  $endpoint = "users/$($userid)"
  if ($PSBoundParameters.ContainsKey("directMembership")) {
    $endpoint = "$($endpoint)/memberOf"
  } 
  elseif ($PSBoundParameters.ContainsKey("transitiveMemberOf")) {  
    $endpoint = "$($endpoint)/transitiveMemberOf"
  }
  # Build the headers we will use to get groups
  $headers = Get-GraphHeader  
  # Create empty list
  $groupList = [System.Collections.Generic.List[PSCustomObject]]@()
  try {
    $uri = $endpoint
    do {
      # Execute call against graph
      $results = Get-GraphAPI -endpoint $uri -headers $headers -beta -Verbose:$VerbosePreference
      # Add results to a list variable
      foreach ($item in $results.results.value) {
        $groupList.Add($item) | Out-Null
      }
      Write-Verbose "Returned $($results.results.value.Count) results. Current result set is $($groupList.Count) items." 
      if ($results.results."@odata.nextLink") {
        $uri = [REGEX]::Match($results.results."@odata.nextLink", "users.*").Value
      }
    }while ($null -ne $results.results."@odata.nextLink")     
  }
  catch {
    throw $_
  }    
  return $groupList
}
#EndRegion '.\Public\Get-GraphUserGroups.ps1' 46
#Region '.\Public\Move-GraphMail.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to move emails between folders in a mailbox
  .PARAMETER id
  The id of the mail message we are acting on
  .PARAMETER emailAddress
  The email address of the account that we are reading from
  .PARAMETER folder
  The id of the folder that we are moving the message to
#>

function Move-GraphMail{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$emailAddress,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$folder
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  $headers = Get-GraphHeader
  # Body Content
  $body = @{
    "destinationId" = $folder
  } | ConvertTo-Json 
  $uri = "https://graph.microsoft.com/beta/users/$($emailAddress)/messages/$($id)/move"
  $results = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode
  # Return Results
  if($statusCode -in (200,201)){
    return $results
  }
  else{
    throw "Unable to move email."
  }      
}
#EndRegion '.\Public\Move-GraphMail.ps1' 36
#Region '.\Public\New-GraphGroup.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to create a new Entra ID group via graph
  .PARAMETER displayName
  The display name of the group
  .PARAMETER mailEnabled
  If the group should be mail enabled, default false
  .PARAMETER mailNickname
  What the mailnickname will be, required even if mailenabled is false
  .PARAMETER description
  The description for the group
  .PARAMETER securityEnabled
  If the group should be security enabled, default true
#>

function New-GraphGroup{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][string]$displayName,
    [Parameter()][bool]$mailEnabled = $false,
    [Parameter(Mandatory = $true)][string]$mailNickname,
    [Parameter()][string]$description,
    [Parameter()][bool]$securityEnabled = $true
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Build the headers we will use to get groups
  $headers = Get-GraphHeader  
  # Variables
  $body = $PsBoundParameters | ConvertTo-Json  
  # Base URI for resource call
  $uri = "https://graph.microsoft.com/beta/groups"
  try{
    # Execute call against graph
    $results = Invoke-RestMethod -Method Post -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode    
    return $results
  }
  catch{
    throw "Unable to create group. $($_.Exception.Message)"
  }
  
}
#EndRegion '.\Public\New-GraphGroup.ps1' 44
#Region '.\Public\Remove-GraphDevice.ps1' 0
function Remove-GraphDevice{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Get Graph Headers for Call
  $headers = Get-GraphHeader  
  # URI Endpoint
  $endpoint = "devices/$($id)"
  try{
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    Invoke-RestMethod -Method Delete $uri -Headers $headers -StatusCodeVariable statusCode  #| Out-Null
  }
  catch{
    throw "Unable to delete devices. $($_.Exception.Message)"
  }   
}
#EndRegion '.\Public\Remove-GraphDevice.ps1' 21
#Region '.\Public\Remove-GraphGroupMember.ps1' 0
function Remove-GraphGroupMember{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$groupId,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string[]]$ids
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # Get Graph Headers for Call
  $headers = Get-GraphHeader 
  try{
    $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
    $batches = [System.Collections.Generic.List[PSCustomObject]]@()
    for($i = 1; $i -le $ids.Count; ++$i){
      $obj = [PSCustomObject]@{
        "id" = $i
        "method" = "DELETE"
        "url" = "/groups/$($groupId)/members/$($ids[$i-1])/`$ref"
      }      
      $batchObj.Add($obj) | Out-Null        
      if($($i % 20) -eq 0){
        $batches.Add($batchObj) | Out-Null
        $batchObj = $null
        $batchObj = [System.Collections.Generic.List[PSCustomObject]]@()
      }      
    }
    $batches.Add($batchObj) | Out-Null
    foreach($batch in $batches){
      $json = [PSCustomObject]@{
        "requests" = $batch
      } | ConvertTo-JSON -Depth 5
      $results = Invoke-RestMethod -Method "POST" -Uri "https://graph.microsoft.com/beta/`$batch" -Headers $headers -Body $json
    }
  }
  catch{
    throw "Unable to remove members. $($_.Exception.Message)"
  }      
}
#EndRegion '.\Public\Remove-GraphGroupMember.ps1' 41
#Region '.\Public\Remove-GraphIntuneApp.ps1' 0
function Remove-GraphIntuneApp{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$applicationid
  )
  # Invoke graph API to remove the application
  $endpoint = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps/$($applicationid)"
  $headers = Get-GraphHeader
  Invoke-RestMethod -Method Delete -Uri $endpoint -Headers $headers -StatusCodeVariable statusCode | Out-Null
}
#EndRegion '.\Public\Remove-GraphIntuneApp.ps1' 11
#Region '.\Public\Remove-GraphIntuneDevicePrimaryUser.ps1' 0
function Remove-GraphIntuneDevicePrimaryUser{
  [CmdletBinding()]
  param(
    [parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$deviceId
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  $endpoint = "deviceManagement/managedDevices/$($deviceId)/users/`$ref"
  $headers = Get-GraphHeader
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  Invoke-RestMethod -method "DELETE" -Uri $uri -Headers $headers -StatusCodeVariable "statusCode"  
}
#EndRegion '.\Public\Remove-GraphIntuneDevicePrimaryUser.ps1' 14
#Region '.\Public\Remove-GraphMailRule.ps1' 0
function Remove-GraphMailRule{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true, ParameterSetName = 'userPrincipalName')][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Alias("id")][Parameter(Mandatory = $true, ParameterSetName = 'userid')][ValidateNotNullOrEmpty()][string]$userid,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$ruleid
  )  
  # Confirm we have a valid graph token
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userPrincipalName)/mailFolders/inbox/messageRules/$($ruleid)"
  }
  if ($PSBoundParameters.ContainsKey("userid")) { 
    $endpoint = "https://graph.microsoft.com/beta/users/$($userid)/mailFolders/inbox/messageRules/$($ruleid)"
  }
  $headers = Get-GraphHeader
  Invoke-RestMethod -Method Delete -Uri $endpoint -Headers $headers -StatusCodeVariable statusCode | Out-Null
}
#EndRegion '.\Public\Remove-GraphMailRule.ps1' 21
#Region '.\Public\Remove-GraphManagedDevice.ps1' 0
function Remove-GraphManagedDevice{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  # Get Graph Headers for Call
  $headers = Get-GraphHeader  
  # URI Endpoint
  $endpoint = "deviceManagement/managedDevices/$($id)"
  try{
    $uri = "https://graph.microsoft.com/beta/$($endpoint)"
    Invoke-RestMethod -Method Delete -Uri $uri -Headers $headers -StatusCodeVariable statusCode | Out-Null
  }
  catch{
    throw "Unable to delete devices. $($_.Exception.Message)"
  }   
}
#EndRegion '.\Public\Remove-GraphManagedDevice.ps1' 21
#Region '.\Public\Send-GraphMailMessage.ps1' 0
function Send-GraphMailMessage{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$from,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$subject,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$message,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string[]]$to,
    [Parameter()][ValidateNotNullOrEmpty()][string[]]$cc,
    [Parameter()][ValidateNotNullOrEmpty()][string[]]$bcc,
    [Parameter()][ValidateSet("html","text")][string]$contenttype = "html",
    [Parameter(Mandatory = $false)][switch]$savetosentitems
  )
  # Confirm we have a valid graph token
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }
  $mailbody = @{
    "message" = @{
      "subject" = $subject
      "body" = @{
        "contentType" = $contenttype
        "content" = $message
      }
    }
    "saveToSentItems" = $savetosentitems.IsPresent
  }
  # Loop through recipients and add them as appropriate
  $mailto = [System.Collections.Generic.List[Hashtable]]@()
  $mailcc = [System.Collections.Generic.List[Hashtable]]@()
  $mailbcc = [System.Collections.Generic.List[Hashtable]]@()
  foreach($item in $to){
    $obj = @{
      "emailAddress" = @{
        "address" = $item
      }
    }
    $mailto.add($obj) | Out-Null
  }
  foreach($item in $cc){
    $obj = @{
      "emailAddress" = @{
        "address" = $item
      }
    }
    $mailcc.add($obj) | Out-Null
  }
  foreach($item in $bcc){
    $obj = @{
      "emailAddress" = @{
        "address" = $item
      }
    }
    $mailbcc.add($obj) | Out-Null
  }    
  $mailbody.message.add("toRecipients",$mailto)
  if($mailcc){
    $mailbody.message.add("ccRecipients",$mailcc)
  }
  if($mailbcc){
    $mailbody.message.add("bccRecipients",$mailbcc)
  }
  # Mail endpoint
  $uri = "https://graph.microsoft.com/beta/users/$($from)/sendMail"
  # Get Graph Header
  $headers = Get-GraphHeader  
  # Send Email
  Invoke-RestMethod -Method POST -Uri $uri -Headers $headers -Body ($mailbody | ConvertTo-Json -Depth 5) -StatusCodeVariable statuscode
  return $statuscode
}
#EndRegion '.\Public\Send-GraphMailMessage.ps1' 70
#Region '.\Public\Set-GraphAutopilotInformation.ps1' 0
function Set-GraphAutopilotInformation {
  param (
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$deviceId,
    [Parameter()][ValidateNotNullOrEmpty()][string]$userPrincipalName,
    [Parameter()][ValidateNotNullOrEmpty()][string]$groupTag,
    [Parameter()][ValidateNotNullOrEmpty()][string]$deviceName
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  $endpoint = "deviceManagement/windowsAutopilotDeviceIdentities/$($deviceId)/UpdateDeviceProperties"
  $headers = Get-GraphHeader
  # Create the body
  $body = @{}
  $clear = @{}
  if ($PSBoundParameters.ContainsKey("userPrincipalName")) {
    $body.Add("userPrincipalName",$userPrincipalName) | Out-Null
  }
  if ($PSBoundParameters.ContainsKey("groupTag")) {
    $body.Add("groupTag",$groupTag) | Out-Null
    $clear.Add("groupTag","") | Out-Null
  }
  if ($PSBoundParameters.ContainsKey("displayName")) {
    $body.Add("displayName",$displayName) | Out-Null
  }
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  if($clear.count -gt 0){
    Invoke-RestMethod -Method "POST" -URI $uri -Headers $headers -Body ($clear | ConvertTo-Json) -StatusCodeVariable "statusCode"
    Start-Sleep -Seconds 5
    Invoke-RestMethod -Headers $headers -Uri "https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotSettings/sync" -Method "POST"  
  }  
  if($body.count -gt 0){
    Invoke-RestMethod -Method "POST" -URI $uri -Headers $headers -Body ($body | ConvertTo-Json) -StatusCodeVariable "statusCode"
    Start-Sleep -Seconds 5
  }   
}
#EndRegion '.\Public\Set-GraphAutopilotInformation.ps1' 37
#Region '.\Public\Set-GraphIntuneDevicePrimaryUser.ps1' 0
function Set-GraphIntuneDevicePrimaryUser{
  param(
    [parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$deviceId,
    [parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$userId
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  $endpoint = "deviceManagement/managedDevices/$($deviceId)/users/`$ref"
  $headers = Get-GraphHeader
  $Body = @{
    "@odata.id" = "https://graph.microsoft.com/beta/users/$($userId)"
  }
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  Invoke-RestMethod -method "POST" -Uri $uri -Headers $headers -body ($body | ConvertTo-JSON) -StatusCodeVariable "statusCode"
}
#EndRegion '.\Public\Set-GraphIntuneDevicePrimaryUser.ps1' 17
#Region '.\Public\Set-GraphMailRead.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is designed to mark a specific email as read
  .PARAMETER id
  The id of the mail message we are acting on
  .PARAMETER emailAddress
  The email address of the account that we are reading from
#>

function Set-GraphMailRead{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$id,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$emailAddress
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }  
  $headers = Get-GraphHeader
  # Body Content
  $body = @{
    "isRead" = $true
  } | ConvertTo-Json
  # Execute Graph Call
  $uri = "https://graph.microsoft.com/beta/users/$($emailAddress)/messages/$($id)"
  $results = Invoke-RestMethod -Method Patch -Uri $uri -Headers $headers -Body $body -StatusCodeVariable statusCode
  # Return Results
  if($statusCode -in (200,201)){
    return $results
  }
  else{
    throw "Unable to mark email as read."
  }  
}
#EndRegion '.\Public\Set-GraphMailRead.ps1' 34
#Region '.\Public\Test-GraphAcessToken.ps1' 0
<#
  .DESCRIPTION
  This cmdlet is tests to see if the passed variable is not null, and expires in less than 10 minutes
  .PARAMETER token
  The current access tokenb variable
#>

function Test-GraphAcessToken{
  [CmdletBinding()]
  param(
    [Parameter()][System.Object]$token
  )
  if(!$token){
    return $false
  }
  $expiryTime = $token.ExpiresOn - (Get-Date)
  if($expiryTime.Minutes -lt 10){
    return $false
  }
  else{
    return $true
  }
}
#EndRegion '.\Public\Test-GraphAcessToken.ps1' 23
#Region '.\Public\Test-GraphIntuneAPNCertificate.ps1' 0
function Test-GraphIntuneAPNCertificate{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$days,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailfrom,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailto,
    [Parameter()][ValidateNotNullOrEmpty()][string]$teamswebhook
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  } 
  # Get the APN Certificate
  $APNCertificate = Get-GraphIntuneAPNCertificate
  # Times for Certificate
  $APNExpDate = $APNCertificate.expirationDateTime
  $APNIdentifier = $APNCertificate.appleIdentifier
  $APNExpShortDate = $APNExpDate.ToShortDateString()  
  # Set Status as null
  $APNExpirationStatus = $null
  # If the certificate has already expired
  if ($APNExpDate -lt (Get-Date)) {
    $APNExpirationStatus = "Apple MDM Push certificate has already expired"
  }
  else{
    $APNDaysLeft = ($APNExpDate - (Get-Date))
    if ($APNDaysLeft.Days -le $APNCertificateDays) {
      $APNExpirationStatus = "Apple MDM Push certificate expires in $($APNDaysLeft.Days) days"
    }
  }
  if($APNExpirationStatus -and $teamswebhook){
    $message = @{
      "webhook"           = $teamswebhook
      "summary"           = "Intune Apple Notification"
      "activityimageuri"  = "https://dev.azure.com/jeremyputman/71648e28-a38f-4acc-bafa-aa569ba7b3f8/_apis/git/repositories/d80cf88f-316e-4d8d-b8f5-d40311acc791/items?path=/Resources/Images/warning.png&%24format=octetStream"
      "title"             = $APNExpirationStatus
      "activitytitle"     = "Action Required!"
      "activitytext"      = "Must be renewed by IT Admin before the expiry date."
      "facts"             = [ordered]@{
                          "Connector:"    = "Apple Push Notification Certificate"
                          "Status:"       = $APNExpirationStatus
                          "AppleID:"      = $APNIdentifier
                          "Expiry Date:"  = $APNExpShortDate        
      }
    }
    Send-TeamsMessage @message | Out-Null
  }
  if($APNExpirationStatus -and $emailfrom -and $emailto){
    $message = @{
      "from" = $emailfrom
      "to" = $emailto
      "subject" = $APNExpirationStatus
      "savetosentitems" = $true
      "message" = "
      <strong style='font-size:14px;'>Action Required!</strong><br/><br/>
      <strong>Connector:</strong> Apple Push Notification Certificate<br/>
      <strong>Status:</strong> $($APNExpirationStatus)<br/>
      <strong>AppleID:</strong> $($APNIdentifier)<br/>
      <strong>Expiry Date:</strong> $($APNExpShortDate)<br/>
      "

    }
    Send-GraphMailMessage @message | Out-Null
  }
  return $APNExpirationStatus
}
#EndRegion '.\Public\Test-GraphIntuneAPNCertificate.ps1' 65
#Region '.\Public\Test-GraphIntuneDEPCertificate.ps1' 0
function Test-GraphIntuneDEPCertificate{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$days,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailfrom,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailto,
    [Parameter()][ValidateNotNullOrEmpty()][string]$teamswebhook
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  # List of Alerts
  $alerts = [System.Collections.Generic.List[Hashtable]]@()
  # Get DEP Tokens
  $DEPTokens = Get-GraphIntuneDEPCertificate
  foreach($DEP in $DEPTokens){
    $DEPTokenDaysLeft = ($DEP.tokenExpirationDateTime - (Get-Date))
    if ($DEPTokenDaysLeft.Days -le $days) {
      $obj = [ordered]@{
        "Status" = "Apple DEP Token expires in $($DEPTokenDaysLeft.Days) days"
        "appleid" = $DEP.appleIdentifier
        "expiry" = $DEP.tokenExpirationDateTime.ToShortDateString()
        "displayname" = $DEP.tokenName
      }
      $alerts.add($obj) | Out-Null
    }
  }
  if($alerts -and $teamswebhook){
    foreach($item in $alerts){
      $message = @{
        "webhook"           = $teamswebhook
        "summary"           = "Intune Apple Notification"
        "activityimageuri"  = "https://dev.azure.com/jeremyputman/71648e28-a38f-4acc-bafa-aa569ba7b3f8/_apis/git/repositories/d80cf88f-316e-4d8d-b8f5-d40311acc791/items?path=/Resources/Images/warning.png&%24format=octetStream"
        "title"             = $item.Status
        "activitytitle"     = "Action Required!"
        "activitytext"      = "Must be renewed by IT Admin before the expiry date."
        "facts"             = [ordered]@{
                            "Connector:"    = "Apple DEP Token"
                            "Status:"       = $item.Status
                            "Display Name:" = $item.displayname
                            "AppleID:"      = $item.appleid
                            "Expiry Date:"  = $item.expiry      
        }
      }
      Send-TeamsMessage @message | Out-Null      
    }
  }
  if($alerts -and $emailfrom -and $emailto){
    foreach($item in $alerts){
      $message = @{
        "from" = $emailfrom
        "to" = $emailto
        "subject" = $item.Status
        "savetosentitems" = $true
        "message" = "
        <h2>Action Required!</h2>
        <strong>Connector:</strong> Apple DEP Token<br/>
        <strong>Status:</strong> $($item.Status)<br/>
        <strong>Display Name:</strong> $($item.displayname)<br/>
        <strong>AppleID:</strong> $($item.appleid)<br/>
        <strong>Expiry Date:</strong> $($item.expiry)<br/>
        "

      }
      Send-GraphMailMessage @message | Out-Null      
    }
  }
  return $alerts  
}
#EndRegion '.\Public\Test-GraphIntuneDEPCertificate.ps1' 69
#Region '.\Public\Test-GraphIntuneLicense.ps1' 0
function Test-GraphIntuneLicense{
  [CmdletBinding()]
  param(
    [parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$userId
  )
  if (!$(Test-GraphAcessToken $script:graphAccessToken)) {
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  $endpoint = "deviceAppManagement/managedAppStatuses('userstatus')?userId=$($userId)"
  $headers = Get-GraphHeader
  $uri = "https://graph.microsoft.com/beta/$($endpoint)"
  $result = Invoke-RestMethod -Method "GET" -URI $uri -Headers $headers -StatusCodeVariable "statusCode"
  $license = $result.content.validationStatuses | Where-Object { $_.validationName -eq 'Intune License' }
  if($license.State -eq 'Pass'){
    return $true
  }
  else{
    return $false
  }
}
#EndRegion '.\Public\Test-GraphIntuneLicense.ps1' 21
#Region '.\Public\Test-GraphIntuneVPPCertificate.ps1' 0
function Test-GraphIntuneVPPCertificate{
  [CmdletBinding()]
  param(
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$days,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailfrom,
    [Parameter()][ValidateNotNullOrEmpty()][string]$emailto,
    [Parameter()][ValidateNotNullOrEmpty()][string]$teamswebhook
  )
  if(!$(Test-GraphAcessToken $script:graphAccessToken)){
    throw "Please Call Get-GraphAccessToken before calling this cmdlet"
  }   
  # List of Alerts
  $alerts = [System.Collections.Generic.List[Hashtable]]@()
  # Get VPP Tokens
  $VPPTokens = Get-GraphIntuneVPPCertificate
  foreach($VPP in $VPPTokens){
    # Check if the token is current valid
    if ($VPP.state -ne 'valid') {
      $obj = [ordered]@{
        "Status" = "Apple VPP Token is not valid, new token required"
        "appleid" = $VPP.appleId
        "expiry" = $VPP.expirationDateTime.ToShortDateString()
        "displayname" = $VPP.displayName
      }
      $alerts.add($obj) | Out-Null
    }
    else{
      $VPPTokenDaysLeft = ($VPP.expirationDateTime - (Get-Date))
      if ($VPPTokenDaysLeft.Days -le $days) {
        $obj = [ordered]@{
          "Status" = "Apple VPP Token expires in $($VPPTokenDaysLeft.Days) days"
          "appleid" = $VPP.appleId
          "expiry" = $VPP.expirationDateTime.ToShortDateString()
          "displayname" = $VPP.displayName
        }
        $alerts.add($obj) | Out-Null        
      }
    }
  }
  if($alerts -and $teamswebhook){
    foreach($item in $alerts){
      $message = @{
        "webhook"           = $teamswebhook
        "summary"           = "Intune Apple Notification"
        "activityimageuri"  = "https://dev.azure.com/jeremyputman/71648e28-a38f-4acc-bafa-aa569ba7b3f8/_apis/git/repositories/d80cf88f-316e-4d8d-b8f5-d40311acc791/items?path=/Resources/Images/warning.png&%24format=octetStream"
        "title"             = $item.Status
        "activitytitle"     = "Action Required!"
        "activitytext"      = "Must be renewed by IT Admin before the expiry date."
        "facts"             = [ordered]@{
                            "Connector:"    = "Apple VPP Token"
                            "Status:"       = $item.Status
                            "Display Name:" = $item.displayname
                            "AppleID:"      = $item.appleid
                            "Expiry Date:"  = $item.expiry      
        }
      }
      Send-TeamsMessage @message | Out-Null      
    }
  }
  if($alerts -and $emailfrom -and $emailto){
    foreach($item in $alerts){
      $message = @{
        "from" = $emailfrom
        "to" = $emailto
        "subject" = $item.Status
        "savetosentitems" = $true
        "message" = "
        <h2>Action Required!</h2>
        <strong>Connector:</strong> Apple VPP Token<br/>
        <strong>Status:</strong> $($item.Status)<br/>
        <strong>Display Name:</strong> $($item.displayname)<br/>
        <strong>AppleID:</strong> $($item.appleid)<br/>
        <strong>Expiry Date:</strong> $($item.expiry)<br/>
        "

      }
      Send-GraphMailMessage @message | Out-Null      
    }
  }
  return $alerts
}
#EndRegion '.\Public\Test-GraphIntuneVPPCertificate.ps1' 81