microsoftgraph / msgraph-sdk-serviceissues

Tracks service issues for follow up.
5 stars 0 forks source link

[QUERY] Trying to receive "deviceCompliancePolicySettingState" objects #113

Open Hipster74 opened 3 years ago

Hipster74 commented 3 years ago

Query/Question Trying to receive "deviceCompliancePolicySettingState" objects from Graph Api but receives nothing.

https://docs.microsoft.com/en-us/graph/api/resources/intune-deviceconfig-devicecompliancepolicysettingstate?view=graph-rest-1.0

Works perfectly when doing it with powershell and plain Invoke-Restmethod to this example URL:

https://graph.microsoft.com/1.0/deviceManagement/managedDevices/$($device.id)/deviceCompliancePolicyStates/$($pol.id)/settingStates

This will give me a collection of "deviceCompliancePolicySettingState" as you can expect.

But, when using the .NET SDK I'm unable to get these objects when I try for example this approach:

var managedDevices = await graphClient.DeviceManagement.ManagedDevices.Request().GetAsync();

foreach (var d in managedDevices) { //Left out code for page iteration
var compliancePolStates = await graphClient.DeviceManagement.ManagedDevices[d.id].DeviceCompliancePolicyStates.Request().GetAsync();

foreach (var s in compliancePolStates) {

_logger.LogInformation($"SettingStates found: {s.SettingStates.Count(); //Always 0, property is of what I believe the correct type of IEnumerable<DeviceCompliancePolicySettingState>}");

}

Am I doing something wrong in my approach, been trying all different methods that I can come up with, this one is the most straight forward and should be the way to go?

Environment:

andrueastman commented 3 years ago

Hey @Hipster74,

Thanks for raising this issue.

The code snippet you mentionedbelow actually ends up making the request to https://graph.microsoft.com/1.0/deviceManagement/managedDevices/$($device.id)/deviceCompliancePolicyStates/ and not https://graph.microsoft.com/1.0/deviceManagement/managedDevices/$($device.id)/deviceCompliancePolicyStates/$($pol.id)/settingStates

var compliancePolStates = await graphClient.DeviceManagement.ManagedDevices[d.id].DeviceCompliancePolicyStates.Request().GetAsync();

Are you able to obtain results if you modify the code to something like this?

var settingState = await graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].Request().GetAsync();

// You can also ensure the property you want is returned using a select statement
// var settingState = await graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].Request().Select("settingStates").GetAsync();

Console.WriteLine($"SettingStates found: {settingState.SettingStates.Count()}");

`Microsoft Graph won't return all the nested properties by default if the request is not specific enough hence the empty collection.

Hipster74 commented 3 years ago

Hi!

Tried this:

var settingState = await graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].Request().GetAsync();

Gives me:

No method match route template[2021-09-13T08:03:58.933Z] Message: No OData route exists that match template ~/singleton/navigation/key/navigation/key with http verb GET for request /DeviceConfiguration_2108/StatelessDeviceConfigurationFEService/deviceManagement/managedDevices('69efgt24-41e5-4803-a0aa-c6906cd7c796')/deviceCompliancePolicyStates('09cdfghy-f1d0-4437-86e5-01c924567126')

Also tried this:

var compliancePolStates = await graphClient.DeviceManagement.ManagedDevices[d.id].DeviceCompliancePolicyStates.Request().Select("settingStates").GetAsync();

Gives me no error, but settingStates collection is still 0 in all policies.

andrueastman commented 3 years ago

Hey @Hipster74,

Maybe this could help out to make the request in the same way that works for you.

var requestUrl = graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].AppendSegmentToRequestUrl("settingStates");
var baseRequest = new BaseRequest(requestUrl, graphClient)
{
    Method = HttpMethods.GET
};
var settingStates = await baseRequest.SendAsync<IEnumerable<DeviceComplianceSettingState>>(null, CancellationToken.None);

Are you also able to share the link to the documentation which helped you find how to make the original request? The link you provided earlier, does not suggest how the request to fetch the states should be done. Ideally the sample below should work as settingStates is a property inside the DeviceCompliancePolicyState but we will need to investigate futher.

var settingState = await graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].Request().Select("settingStates").GetAsync();

Console.WriteLine($"SettingStates found: {settingState.SettingStates.Count()}");
Hipster74 commented 3 years ago

Hi again.

Tried this(changed IEnumerable type to DeviceCompliancePolicySettingState since that should be the returned type I assume). Also tried with DeviceComplianceSettingState as you had in your original example, but same result.

var settingStates = await baseRequest.SendAsync<IEnumerable<DeviceComplianceSettingState>>(null, CancellationToken.None);

Got this:

One or more errors occurred. (The JSON value could not be converted to System.Collections.Generic.IEnumerable`1[Microsoft.Graph.DeviceCompliancePolicySettingState

I don't have documentation for the endpoint used when running this in powershell, I think that URL comes from the Azure portal and using the F12 browser tools to intercept the api calls.

Yes, this should be as simple as doing something like this in my opinion:

var settingState = await graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].Request().Select("settingStates").GetAsync();

Console.WriteLine($"SettingStates found: {settingState.SettingStates.Count()}");

settingStates collection is described in the graph metadata , but since it is empty when using the SDK, isn't this considered a bug?

I thought the SDK was auto generated from the graph metadata, maybe there is something not really working there.

<EntityType Name="deviceCompliancePolicyState" BaseType="graph.entity">
<Property Name="displayName" Type="Edm.String"/>
<Property Name="platformType" Type="graph.policyPlatformType" Nullable="false"/>
<Property Name="settingCount" Type="Edm.Int32" Nullable="false"/>
<Property Name="settingStates" Type="Collection(graph.deviceCompliancePolicySettingState)"/>
<Property Name="state" Type="graph.complianceStatus" Nullable="false"/>
<Property Name="userId" Type="Edm.String"/>
<Property Name="userPrincipalName" Type="Edm.String"/>
<Property Name="version" Type="Edm.Int32" Nullable="false"/>
</EntityType>
andrueastman commented 3 years ago

settingStates collection is described in the graph metadata , but since it is empty when using the SDK, isn't this considered a bug?

Yeah. That would be case but we would first need to confirm what the response from the API is to narrow down if the issue occurs in the SDK or it is something that needs to be fixed from the API. Since you are getting an empty collection from the SDK it means that the API is not really returning anything for the collection.

Are you able to try building the request on Graph Explorer and confirm that the sample request has the settingsState property populated?

https://developer.microsoft.com/en-us/graph/graph-explorer?request=deviceManagement%2FmanagedDevices%2F%7Bdevice-id%7D%2FdeviceCompliancePolicyStates%2F%7Bpolicy-id%7D%3F%24select%3DsettingStates&method=GET&version=v1.0&GraphUrl=https://graph.microsoft.com

Hipster74 commented 3 years ago

Tried it in insomnia since I was unable to use my client credentials in graph explorer(token set in authorization header), but this example URL gave me an error:

https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/f6056jf7-e735-r745-91cf-b3ac56df234c/deviceCompliancePolicyStates/b3523b5-0404-441a-93b0-3191f6773aea?$select=settingStates

{
  "error": {
    "code": "No method match route template",
    "message": "No OData route exists that match template ~/singleton/navigation/key/navigation/key with http verb GET for request /DeviceConfiguration_2108/StatelessDeviceConfigurationFEService/deviceManagement/managedDevices('f60268f7-e735-4f45-91cf-b3ac56df234c')/deviceCompliancePolicyStates('b35839f5-0404-441a-93b0-3191f1d73aea').",
    "innerError": {
      "date": "2021-09-14T07:36:53",
      "request-id": "73f795c0-d4d9-40fd-9e6f-0a76d9412a02",
      "client-request-id": "73f795c0-d4d9-40fd-9e6f-0a76d9412a02"
    }
  }
}

This on the other hand worked(as expected since it is the same as the one I used in powershell):

https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/f6056jf7-e735-r745-91cf-b3ac56df234c/deviceCompliancePolicyStates/b3523b5-0404-441a-93b0-3191f6773aea/settingStates

And gave me something like this back:

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#deviceManagement/managedDevices('f645y8f7-e735-4f45-91cf-b3ac56df234c')/deviceCompliancePolicyStates('b35hj8f5-0404-441a-93b0-3191f1d73aea')/settingStates",
  "value": [
    {
      "setting": "Windows10CompliancePolicy.AntiSpywareRequired",
      "settingName": null,
      "instanceDisplayName": "",
      "state": "compliant",
      "errorCode": 0,
      "errorDescription": "No error code",
      "userId": "3356ee79-b462-4a51-a0ad-b7567i24b1bc",
      "userName": null,
      "userEmail": null,
      "userPrincipalName": "john.doe@contoso.com",
      "currentValue": "",
      "sources": [
        {
          "id": "B35839F5-0404-441A-93B0-3191Fdfer3AEA",
          "displayName": "CloudClient-Baseline Policy",
          "sourceType": "deviceConfiguration"
        }
      ]
    },
    {
      "setting": "Windows10CompliancePolicy.DefenderEnabled",
      "settingName": null,
      "instanceDisplayName": "",
      "state": "compliant",
      "errorCode": 0,
      "errorDescription": "No error code",
      "userId": "3356ee79-jk82-4a51-a0ad-b7345d24b1bc",
      "userName": null,
      "userEmail": null,
      "userPrincipalName": "jane.doe@contoso.com",
      "currentValue": "",
      "sources": [
        {
          "id": "B35839F5-0404-441A-93B0-31923445673AEA",
          "displayName": "CloudClient-Baseline Policy",
          "sourceType": "deviceConfiguration"
        }
      ]
    }
  ]
}
andrueastman commented 3 years ago

Thanks for getting back with this @Hipster74

this example URL gave me an error: https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/f6056jf7-e735-r745-91cf-b3ac56df234c/deviceCompliancePolicyStates/b3523b5-0404-441a-93b0-3191f6773aea?$select=settingStates

We will need to raise this with the relevant API team to get further guidance on whether this is expected.

This on the other hand worked(as expected since it is the same as the one I used in powershell): https://graph.microsoft.com/v1.0/deviceManagement/managedDevices/f6056jf7-e735-r745-91cf-b3ac56df234c/deviceCompliancePolicyStates/b3523b5-0404-441a-93b0-3191f6773aea/settingStates

The sdk currently does not really support the querying of properties directly as this query does. The metadata would need to specify the settingStates property as either a NavigationProperty or one would need to query the parent object and this property would come back with the properties inside(which fails as above).

For now, you can use a workaround something similar to this as we feed this back to the relevant team.

var requestUrl = graphClient.DeviceManagement.ManagedDevices["deviceId"].DeviceCompliancePolicyStates["policy-id"].AppendSegmentToRequestUrl("settingStates");
var request = new BaseRequest(requestUrl, graphClient)
{
    Method = HttpMethods.GET
};
var response = await graphClient.HttpProvider.SendAsync(request.GetHttpRequestMessage());
var stringContent = await response.Content.ReadAsStringAsync();
var valueString = JsonDocument.Parse(stringContent).RootElement.GetProperty("value").GetRawText();
var settingStates = graphClient.HttpProvider.Serializer.DeserializeObject<IEnumerable<DeviceCompliancePolicySettingState>>(valueString);
Hipster74 commented 3 years ago

Ok @andrueastman , thank you for the update and the workaround, you been most helpful so far, appreciate it.

petrhollayms commented 7 months ago

Thank you for reporting this issue. This appears to be an issue or limitation with the service APIs. Unfortunately, as the Microsoft Graph SDK team, we do not have ownership of the APIs that are causing you issues. We invite you to create a question about the service API to Microsoft Q&A and tagged with one of the [microsoft-graph-*] tags, that way it will get routed to the appropriate team for them to triage:

https://aka.ms/msgraphsupport or directly https://aka.ms/askgraph

For now, we will close the issue on our side but feel free to open it in the relevant repository if you think the issue is specific to SDK. Please let us know if this helps!

Note: We will close this repository on April 19, 2024.