msgraph-sdk-powershell
msgraph-sdk-powershell copied to clipboard
URLencode seems to cause issues with filters
Here's a filter that works perfectly fine with Graph explorer:
GET https://graph.microsoft.com/beta/users?$filter=assignedPlans/any(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)&$count=true
(advanced query, so needs the ConsistencyLevel header)

Same request works fine with direct Graph query as well:
$uri = "https://graph.microsoft.com/beta/users?`$filter=assignedPlans/any(c:ServicePlanId eq 57ff2da0-773e-42df-b2af-ffb7a2317929)&`$count=true"
Invoke-WebRequest -Headers $AuthHeader1 -Uri $uri -Verbose -Debug
Trying to run the same in the SDK results in "Get-MgUser_List: Invalid filter clause" error.
Get-MgUser -Filter 'assignedPlans/any(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)' -ConsistencyLevel Eventual -CountVariable count -Verbose -Debug
DEBUG: [CmdletBeginProcessing]: - Get-MgUser begin processing with parameterSet 'List'.
DEBUG: [Authentication]: - AuthType: 'Delegated', AuthProviderType: 'InteractiveAuthenticationProvider', ContextScope: 'CurrentUser', AppName: 'Microsoft Graph PowerShell'.
DEBUG: [Authentication]: - Scopes: [AuditLog.Read.All, DeviceManagementServiceConfig.Read.All, Directory.AccessAsUser.All, Directory.Read.All, email, Group.Read.All, Mail.Read, Mail.ReadWrite, OnlineMeetingArtifact.Read.All, OnlineMeetings.Read, openid, profile, Sites.Read.All, User.Read, User.Read.All, User.ReadWrite.All].
DEBUG: ============================ HTTP REQUEST ============================
HTTP Method:
GET
Absolute Uri:
https://graph.microsoft.com/beta/users?$filter=assignedPlans%2Fany%28c%3AServicePlanId%2Beq%2B57ff2da0-773e-42df-b2af-ffb7a2317929%29&$count=true
Headers:
ConsistencyLevel : Eventual
Looking at the above, the URLencode seems to be causing the issue. Specifically, replacing the space (or "+") sign within the lambda operator statement. So, while this does NOT work:
https://graph.microsoft.com/beta/users?$filter=assignedPlans%2Fany%28c%3AServicePlanId%2Beq%2B57ff2da0-773e-42df-b2af-ffb7a2317929%29&$count=true
this will:
https://graph.microsoft.com/beta/users?$filter=assignedPlans%2Fany(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)&$count=true
So the potential solution is to avoid encoding the plus sign (or spaces) within the lambda payload.
Tested on latest module version, 1.9.6
@michevnew, -Filter expects you to pass a filter expression that is unencoded. In the example above, the filter expression being passed to -Filter is already encoded with + for space thus the error. This can be reproduced using:
➜ [System.Web.HttpUtility]::UrlEncode("assignedPlans/any(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)")
# Outputs -> assignedPlans%2fany(c%3aServicePlanId%2beq%2b57ff2da0-773e-42df-b2af-ffb7a2317929)
➜ [System.Web.HttpUtility]::UrlDecode("assignedPlans/any(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)")
# Outputs -> assignedPlans/any(c:ServicePlanId eq 57ff2da0-773e-42df-b2af-ffb7a2317929)
Please pass a decoded -Filter expression as the command already handles query parameter encoding for you:
Get-MgUser -Filter 'assignedPlans/any(c:ServicePlanId eq 57ff2da0-773e-42df-b2af-ffb7a2317929)' -ConsistencyLevel Eventual -CountVariable count -Debug
This is the same filter clause you used with Invoke-MgGraphRequest in:
$uri = "https://graph.microsoft.com/beta/users?`$filter=assignedPlans/any(c:ServicePlanId eq 57ff2da0-773e-42df-b2af-ffb7a2317929)&`$count=true"
Invoke-WebRequest -Headers $AuthHeader1 -Uri $uri -Verbose -Debug
We will use this issue as a feature request to track support for both encoded and decoded query parameters.
Thanks for the explanation Peter. I suppose my complaint here is that the PowerShell SDK does not provide the same experience as either the Graph explorer or direct calls via Invoke-WebRequest/Invoke-RestMethod, all of which seem to decode the input and thus handle various permutations. If we are to use a simpler query as an example, all of the variations below work with other tools:
id eq 'fca15ab9-c964-49e5-9531-904bbd5f9160'
id+eq+'fca15ab9-c964-49e5-9531-904bbd5f9160'
id+eq+%27fca15ab9-c964-49e5-9531-904bbd5f9160%27
id eq+%27fca15ab9-c964-49e5-9531-904bbd5f9160'
id+eq 'fca15ab9-c964-49e5-9531-904bbd5f9160%27
(and similar permutations)
I realize those are different products, but it would be nice if you can improve the experience on that front. URL decoding the -Filter input should address this, I believe?
Get-MgUser -Filter $([System.Web.HttpUtility]::UrlDecode("assignedPlans/any(c:ServicePlanId+eq+57ff2da0-773e-42df-b2af-ffb7a2317929)")) -ConsistencyLevel Eventual -CountVariable count -Debug
P.S. As the issue is not only with advanced queries, I've adjusted the title.
I agree with you! The experience can be improved to match existing tools. We will work with the team that owns the code generator to resolve this.
That's right, decoding the -Filter input can be used as a work around/fix. However, the challenge with this approach is HttpUtility class is not available in PowerShell 5.1, which we support. If you are using the command in PowerShell 7+, you should be fine with using [System.Web.HttpUtility]::UrlDecode to decode the filter input.
Closing as fixed by https://github.com/microsoftgraph/msgraph-sdk-powershell/releases/tag/2.0.0-preview6
Hi,
What's the correct way to do it if you want to filter something that actually has a "+" sign?
I wan't to get a user by his ImmutableID. And this often has "+" signs. But this gets translated to " ":
Get-MgUser -filter "onPremisesImmutableId eq 'jcsXNJHNAUyn+8bAc+2XVg=='"
Absolute Uri:
https://graph.microsoft.com/v1.0/users?$filter=onPremisesImmutableId eq %27jcsXNJHNAUyn 8bAc 2XVg%3D%3D%27