Azure AD Graph any $filter syntax - azure-ad-graph-api

I don't completely understand the any syntax from the example provided here under the $filter documentation. Nor can I find any more info about it.
any is supported when querying multi-valued properties. For example: https://graph.windows.net/contoso.com/users?api-version=2013-11-08&$filter=userPrincipalName eq 'Mary#Contoso.com' or proxyAddresses/any(c:c eq 'smtp:Mary#Contoso.com')
What is the c:c part? Seems like a lambda...

What is the c:c part? Seems like lambda...
Yes, you are right. We could get more information about $filter Lambda Operators from this tutorial
OData defines two operators any and all that evaluate a Boolean expression on a collection. They can work on either collection properties or collection of entities.
According to the UserEnity, we could know that proxyAddresses is Collection(Edm.String). So any(c:c eq 'smtp:Mary#Contoso.com') equals to User.proxyAddresses.Where(c=>c.equals("smtp:Mary#Contoso.com").

Yes you are correct. c is a lambda variable here and c eq 'smtp:Mary#Contoso.com' is lambda expression.
proxyAddresses/any(c:c eq 'smtp:Mary#Contoso.com') will return collection of proxyAddresses for which the lambda expression returns true.
More examples and explanation can be found here.

Related

Does PostREST have a null-safe not-equal operator, like IS DISTINCT FROM?

I'm making some simple PostgREST queries on a table with network device properties. It seems that eq and not.eq both exclude null values. I've learned that that's a “feature” of PostgreSQL, and can be worked around with the IS DISTINCT FROM operator, which treats null as a comparable value.
I can't find an equivalent (null-safe not-equals) operator in PostgREST. Is there one?
Simplified example:
# https://example.com/api?select=*&name=like.spam-*
[{
"name":"spam-eggs",
"type":"router",
"sector":"cheese"
},{
"name":"spam-ham",
"type":"router",
"sector":null
}]
not.eq.cheese excludes cheese and null:
# https://example.com/api?select=*&name=like.spam-*&sector=not.eq.cheese
[]
My awkward workaround is using or to include nulls:
# https://example.com/api?select=*&name=like.spam-*&or=(sector.not.eq.cheese,sector.is.null)
[{
"name":"spam-ham",
"type":"router",
"sector":null
}]
Am I stuck with that workaround, or is there an operator like isdistinctfrom, neq-or-null, etc. that I've missed?
I've checked the code and there's no implementation of IS DISTINCT FROM right now. That is, no PostgREST operator translates to it. The only reference I found is in a comment in this file, but it's for a different issue.
So, yes, right now, your workaround would be the closest you can get to the behavior you want. Creating a FUNCTION with a custom query using IS DISTINCT FROM is another alternative, although it requires more heavy lifting.

Why can't I call IEnumerable.Sum() on an array in PowerShell? [duplicate]

I am trying to use LINQ in PowerShell. It seems like this should be entirely possible since PowerShell is built on top of the .NET Framework, but I cannot get it to work. For example, when I try the following (contrived) code:
$data = 0..10
[System.Linq.Enumerable]::Where($data, { param($x) $x -gt 5 })
I get the following error:
Cannot find an overload for "Where" and the argument count: "2".
Never mind the fact that this could be accomplished with Where-Object. The point of this question is not to find an idiomatic way of doing this one operation in PowerShell. Some tasks would be light-years easier to do in PowerShell if I could use LINQ.
The problem with your code is that PowerShell cannot decide to which specific delegate type the ScriptBlock instance ({ ... }) should be cast.
So it isn't able to choose a type-concrete delegate instantiation for the generic 2nd parameter of the Where method. And it also does't have syntax to specify a generic parameter explicitly. To resolve this problem, you need to cast the ScriptBlock instance to the right delegate type yourself:
$data = 0..10
[System.Linq.Enumerable]::Where($data, [Func[object,bool]]{ param($x) $x -gt 5 })
Why does [Func[object, bool]] work, but [Func[int, bool]] does not?
Because your $data is [object[]], not [int[]], given that PowerShell creates [object[]] arrays by default; you can, however, construct [int[]] instances explicitly:
$intdata = [int[]]$data
[System.Linq.Enumerable]::Where($intdata, [Func[int,bool]]{ param($x) $x -gt 5 })
To complement PetSerAl's helpful answer with a broader answer to match the question's generic title:
Note: The following applies up to at least PowerShell 7.2. Direct support for LINQ - with syntax comparable to the one in C# - is being discussed for a future version of PowerShell Core in GitHub issue #2226.
Using LINQ in PowerShell:
You need PowerShell v3 or higher.
You cannot call the LINQ extension methods directly on collection instances and instead must invoke the LINQ methods as static methods of the [System.Linq.Enumerable] type to which you pass the input collection as the first argument.
Having to do so takes away the fluidity of the LINQ API, because method chaining is no longer an option. Instead, you must nest static calls, in reverse order.
E.g., instead of $inputCollection.Where(...).OrderBy(...) you must write [Linq.Enumerable]::OrderBy([Linq.Enumerable]::Where($inputCollection, ...), ...)
Helper functions and classes:
Some methods, such as .Select(), have parameters that accept generic Func<> delegates (e.g, Func<T,TResult> can be created using PowerShell code, via a cast applied to a script block; e.g.:
[Func[object, bool]] { $Args[0].ToString() -eq 'foo' }
The first generic type parameter of Func<> delegates must match the type of the elements of the input collection; keep in mind that PowerShell creates [object[]] arrays by default.
Some methods, such as .Contains() and .OrderBy have parameters that accept objects that implement specific interfaces, such as IEqualityComparer<T> and IComparer<T>; additionally, input types may need to implement IEquatable<T> in order for comparisons to work as intended, such as with .Distinct(); all these require compiled classes written, typically, in C# (though you can create them from PowerShell by passing a string with embedded C# code to the Add-Type cmdlet); in PSv5+, however, you may also use custom PowerShell classes, with some limitations.
Generic methods:
Some LINQ methods themselves are generic and therefore require one or more type arguments.
In PowerShell (Core) 7.2- and Windows PowerShell, PowerShell cannot directly call such methods and must use reflection instead, because it only supports inferring type arguments, which cannot be done in this case; e.g.:
# Obtain a [string]-instantiated method of OfType<T>.
$ofTypeString = [Linq.Enumerable].GetMethod("OfType").MakeGenericMethod([string])
# Output only [string] elements in the collection.
# Note how the array must be nested for the method signature to be recognized.
PS> $ofTypeString.Invoke($null, (, ('abc', 12, 'def')))
abc
def
For a more elaborate example, see this answer.
In PowerShell (Core) 7.3+, you now have the option of specifying type arguments explicitly (see the conceptual about_Calling_Generic_Methods help topic); e.g.:
# Output only [string] elements in the collection.
# Note the need to enclose the input array in (...)
# -> 'abc', 'def'
[Linq.Enumerable]::OfType[string](('abc', 12, 'def'))
The LINQ methods return a lazy enumerable rather than an actual collection; that is, what is returned isn't the actual data yet, but something that will produce the data when enumerated.
In contexts where enumeration is automatically performed, notably in the pipeline, you'll be able to use the enumerable as if it were a collection.
However, since the enumerable isn't itself a collection, you cannot get the result count by invoking .Count nor can you index into the iterator; however, you can use member-access enumeration (extracting the values of a property of the objects being enumerated).
If you do need the results as a static array to get the usual collection behavior, wrap the invocation in [Linq.Enumerable]::ToArray(...).
Similar methods that return different data structures exist, such as ::ToList().
For an advanced example, see this answer.
For an overview of all LINQ methods including examples, see this great article.
In short: using LINQ from PowerShell is cumbersome and is only worth the effort if any of the following apply:
you need advanced query features that PowerShell's cmdlets cannot provide.
performance is paramount - see this article.
If you want to achieve LINQ like functionality then PowerShell has some cmdlets and functions, for instance: Select-Object, Where-Object, Sort-Object, Group-Object. It has cmdlets for most of LINQ features like Projection, Restriction, Ordering, Grouping, Partitioning, etc.
See Powershell One-Liners: Collections and LINQ.
For more details on using Linq and possibly how to make it easier, the article LINQ Through Powershell may be helpful.
I ran accross LINQ, when wanting to have a stable sort in PowerShell (stable: if property to sort by has the same value on two (or more) elements: preserve their order). Sort-Object has a -Stable-Switch, but only in PS 6.1+. Also, the Sort()-Implementations in the Generic Collections in .NET are not stable, so I came accross LINQ, where documentation says it's stable.
Here's my (Test-)Code:
# Getting a stable sort in PowerShell, using LINQs OrderBy
# Testdata
# Generate List to Order and insert Data there. o will be sequential Number (original Index), i will be Property to sort for (with duplicates)
$list = [System.Collections.Generic.List[object]]::new()
foreach($i in 1..10000){
$list.Add([PSCustomObject]#{o=$i;i=$i % 50})
}
# Sort Data
# Order Object by using LINQ. Note that OrderBy does not sort. It's using Delayed Evaluation, so it will sort only when GetEnumerator is called.
$propertyToSortBy = "i" # if wanting to sort by another property, set its name here
$scriptBlock = [Scriptblock]::Create("param(`$x) `$x.$propertyToSortBy")
$resInter = [System.Linq.Enumerable]::OrderBy($list, [Func[object,object]]$scriptBlock )
# $resInter.GetEnumerator() | Out-Null
# $resInter is of Type System.Linq.OrderedEnumerable<...>. We'll copy results to a new Generic List
$res = [System.Collections.Generic.List[object]]::new()
foreach($elem in $resInter.GetEnumerator()){
$res.Add($elem)
}
# Validation
# Check Results. If PropertyToSort is the same as in previous record, but previous sequence-number is higher, than the Sort has not been stable
$propertyToSortBy = "i" ; $originalOrderProp = "o"
for($i = 1; $i -lt $res.Count ; $i++){
if(($res[$i-1].$propertyToSortBy -eq $res[$i].$propertyToSortBy) -and ($res[$i-1].$originalOrderProp -gt $res[$i].$originalOrderProp)){
Write-host "Error on line $i - Sort is not Stable! $($res[$i]), Previous: $($res[$i-1])"
}
}
There is a simple way to make Linq chaining fluent, by setting a using statement to the Linq namespace, Then you can call the where function directly, no need to call the static Where function.
using namespace System.Linq
$b.Where({$_ -gt 0})
$b is an array of bytes, and I want to get all bytes that are greater than 0.
Works perfect.

OrderedDictionary key name at specified index

Given an ordered dictionary, I would like to get the key at index 0. I can of course do a loop, get the key of the first iteration and immediately break out of the loop. But I wonder if there is a way to do this directly?
My Google-Fu has not turned up anything, and some shots in the dark have failed too. I have tried things like
$hash[0].Name
and
$hash.GetEnumerator()[0].Name
I found this discussion about doing it in C#, which lead to this
[System.Collections.DictionaryEntry]$test.Item(0).Key
but that fails too. Is this just something that can't be done, or am I going down the wrong path?
Use the .Keys collection:
$orderedHash = [ordered] #{ foo = 1; bar = 2 }
# Note the use of #(...)
#($orderedHash.Keys)[0] # -> 'foo'
Note:
Use of #(...), the array-subexpression operator, enumerates the .Keys collection and collects its elements in an [object[]] array, which enables access by positional indices.
The .Keys collection itself implements only the System.Collections.ICollection interface, which supports enumeration, but not indexed access.
#(...) to enable indexing will no longer be necessary in PowerShell (Core) 7.3+ (.NET 7+), thanks to an improvement initiated by iRon via GitHub issue #56835: The .Keys collection will then implement the System.Collections.IList interface, which does support positional indexing. Note that this change will only apply to ordered hashtables ([ordered] #{ ... }, System.Collections.Specialized.OrderedDictionary), not also to regular (unordered) hashtables (#{ ... }) or other types implementing the System.Collections.IDictionary interface. However, iRon has created a follow-up proposal to make the .Keys property indexable for all (definition-)ordered and sorted dictionaries - see GitHub issue #63537.
.Name is an alias property provided by PowerShell; the type-native property containing each System.Collections.DictionaryEntry's key is .Key

Identity Operator / Comparison without Implicit Type Conversion

When using PowerShell, occasionally we compare objects of different types. A common scenario being $int -eq $bool (i.e. where 0 -eq $false, 0 -ne $true, and any non-zero value only equals true, but not false).
Mostly that's a good thing; sometimes it's a pain (e.g. if I'm looking for all properties on an object which have value 1, but I don't want all those which have value $true).
Question
Is there an operator which performs this comparison without conversion; i.e. which essentially does the same as JavaScript's identity operator (===);?
Bonus Question
If there is such an operator, is there any tolerance? i.e. whilst I don't want to treat 1 and true as being identical, it would (sometimes) be helpful if I could treat [int]1 and [long]1 as though they are.
PowerShell do not offer such operator directly, but you can use standard .NET method [Object]::Equals to do such comparison.
Note:
It allows to types to implement they own equality comparison by overriding virtual Object.Equals method, thus it possible to have some weird behavior, if some custom type implement it improperly. But all standard .NET types should fine and consider themselves equals only to the instance of the same type.

Why the 'it' in Entity Framework and EntityDataSource examples?

Dumb question I'm sure, but why does Entity Framework EntityDataSource object require the where clause to contain 'it' as the first part of the object selector?
The documentation for the where clause (http://msdn.microsoft.com/en-us/library/cc488531.aspx) states that the string is passed directly to the ObjectQuery(T), so I should be able to pass in (for example) "x.OnlineOrderFlag = TRUE" where x is anything that makes sense in a predicate, however the clause only works if I pass in "it.OnlineOrderFlag = TRUE"
All of the Microsoft examples use 'it' so what am I missing?
Steve Davies
It looks like "it" is just an implicit parameter name. In query expressions this is provided by the range variable, but you don't specify the parameter name in the call to Where, so it looks like it just uses "it" implicitly.
I agree that it's poorly documented though :(