for (;;) {
#Get All Files from the Folder
$FolderItems = @(Get-PnPFolderItem -FolderSiteRelativeUrl $FolderURL -ItemType File)
Write-Host "Total Number of Files in the Folder:" $FolderItems.Count
if ($FolderItems.Count -gt $oldCount) {
foreach ($item in $FolderItems) {
if ($oldFolderItems -contains $item) {
}
else {
Write-Host $item.Name
}
}
}
$oldCount = $FolderItems.Count
$oldFolderItems = $FolderItems
timeout 180
}
It prints all the names instead of the one new item
tl;dr
Replace your foreach
loop with the following call to Compare-Object
:
# Compare the new and the old collection items by their .Name property
# and output the name of those that are unique to the new collection.
Compare-Object -Property Name $FolderItems $oldFolderItems |
Where-Object SideIndicator -eq '<=' |
ForEach-Object Name
You should also initialize $oldFolderItems
to $null
and $oldCount
to 0
, to be safe, and - unless you want all names to be output in the first iteration - change the enclosing if
statement to:
if ($oldFolderItems -and $FolderItems.Count -gt $oldCount) { # ...
Note: The immediate - but inefficient - fix to your attempt would have been the following, for the reasons explained in the next section:
if ($oldFolderItems.Name -contains $item.Name) { # Compare by .Name values
Note: $oldFolderItems.Name
actually returns the array of .Name
property values of the elements in collection $oldFolderItems
, which is a convenient feature named member-access enumeration.
As for what you tried:
It's unclear what .NET type Get-PnPFolderItem
returns instances of, but it's fair to assume that the type is a .NET reference type (as opposed to a value type).
Unless a reference type is explicitly designed to compare its instances based on identifying properties,[1] reference equality is tested for in equality test-based operations such as -contains
(but also in other equality-comparison operations, such as with -in
and -eq
), i.e. only two references to the very same instance are considered equal.
Therefore, using -contains
in your case won't work, because the elements of the collections - even if they conceptually represent the same objects - are distinct instances that compare as unequal.
A simplified example, using System.IO.DirectoryInfo
instances, as output by Get-Item
:
# !! Returns $false, because the two [System.IO.DirectoryInfo]
# !! instances are distinct objects.
@(Get-Item /) -contains (Get-Item /)
Therefore, instances of .NET reference types must be compared by the value of an identifying property (if available, such as .Name
in this case) rather than as a whole.
To discover whether a given instance is one of a .NET reference type, access the type's .IsValueType
property: a return value of $false
indicates a reference type; e.g.:
(Get-Item /).GetType().IsValueType # -> $false -> reference type
# Equivalent, with a type literal
[System.IO.DirectoryInfo].IsValueType # -> $false
[1] A notable example is the [string]
type, which, as an exception, generally behaves like a value type, so that the following is still $true
, despite technically distinct instances being involved: $s1 = 'foo'; $s2 = 'f' + 'oo'; $s1 -eq $s2