Reputation: 746
My apologies if this is a dupe but after searching for some time, I wasn't able to find an answer that worked in my case.
I have a python script that searches for faces in photographs. The python script works fine and I'm now trying to incorporate its output into a csv file that I can use to run some statistics on.
Enter powershell.
Here is my powershell script:
$picts = gci *.jpg
$(foreach ($f in $picts)
{
$obj2 = New-Object System.Object
$obj2 | Add-Member -MemberType NoteProperty -Name fileName -Value $f.Name
$obj2 | Add-Member -MemberType ScriptProperty -Name datumN -Value {
python face_detect_batch.py $f.Name
}
$obj2
}
) | export-csv t.csv
The python script prints a single line containing the filename it was fed along with some info about the photo.
I'm testing the script on a folder that has two jpegs in it, 1.jpg and 2.jpg. If I run the script by hand on each photo, it works as expected.
However, if I run the above script to iterate through the photos I get the following output:
#TYPE System.Object
fileName datumN
1.jpg name: 2.jpg; blurScore: 269; facex: 68; facey: 84; faceWidth: 155; faceHeight:155
2.jpg name: 2.jpg; blurScore: 269; facex: 68; facey: 84; faceWidth: 155; faceHeight:155
The output shows that the script iterates as I expect and adds the two distinct filenames to $obj2
's filename property but when the script property add-member executes, my python script is fed 2.jpg both times.
I've tried feeding [ref]$f.name
and $global:f.name
in the value field of add-member but none of the changes make any difference - I always get 2.jpg being passed to my python script.
Why does the first reference to $f.Name
enumerate the files as expected but the second reference only sees the last jpeg?
Upvotes: 2
Views: 90
Reputation: 440412
Do not use a ScriptProperty
member to create a property whose value should be assigned once, statically - instead, use a NoteProperty
member:
Get-ChildItem *.txt | ForEach-Object {
[pscustomobject] @{
fileName = $_.Name
datumN = python face_detect_batch.py $_.Name
}
} | Export-Csv t.csv
Note how [pscustomobject] @{ ... }
is used to define a custom object indirectly via a hashtable literal, which simplifies its construction.
Value python face_detect_batch.py $_.Name
for key / property datumN
simply invokes python
with every input filename at the time the object is constructed and stores the result in property datumN
, as a one-time operation.
The properties of the resulting [pscustomobject]
instance are implicitly and invariable of type NoteProperty
, i.e., static values.
As for what you tried:
By creating a ScriptProperty
member, you're assigning a piece of code that is run every time the property is accessed.
Thus, it is only later, at the time your objects are exported by Export-Csv
that their .datumN
property is retrieved, causing the script block to run then, at which point $f
happens to contain the last iteration's value.
Upvotes: 2