Problem with if statement in stay_open mode in a Powershell script

Started by maxppp, October 11, 2018, 10:24:54 AM

Previous topic - Next topic

maxppp

Bonjour,

I'm quite a newbie with ExifTool and I need your help

Although my script works perfectly (although very long) with the iterative call of exiftool.exe, I can't handle the -if statement when I use ExifTool in stay_open mode in a Powershell script.
Indeed, when running in stay_open mode, the final result of the iteration is a list of alerts "Warning: The tag 'if' is not defined" as well as a list of all the files contained in the folder to be processed. The script bypasses the if statement and only deals with the second part of my argument.

This script works well:
Quote
$Source ="J:\pour_archivages\People\072" # test : containing 1,000 files, most with IPTC Category ACE, some not ACE
$Cible = "J:\pour_archivages\News\001"    # test :  to receive files with IPTC Category not ACE and not SPO
$total_archd = 0
$total_ACE = 0

$ListeFichiers= Get-ChildItem -Path $Source -file

Foreach ($Fichier in $ListeFichiers) {     
    If (( C:\Users\Administrateur\Documents\mes_scripts\EXIFtool\exiftool.exe -if '$IPTC:Category =~ "/(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i"' -filename $($File.FullName)) -like "File name*") {
        ## above, "File name" is part of the string returned when the condition is fulfilled
        # move-item -path $Fichier .fullname -Destination $cible
        $total_archd ++ # for count testing
    }
    Else {
        $total_ACE ++  # for count testing
    }
}
write-host "total des fichiers reclassés dans News : $total_archd"
write-host "total des fichiers ACE dans People : $total_ACE"

(...) #closing procedures

In the stay_open mode, that part goes wrong:
Quote
## NB: to cut short, all the code for creation of ExifTool object and ExifTool process is fine, so I zap it here

Foreach ($File in $ListeFichiers) {
[string]$ArgList ="-if '$IPTC:Category =~ `"/(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i`"'`n-filename`n$($File.FullName)"
If (($exiftoolproc.StandardInput.WriteLine("$ArgList`n-execute`n")) -like "File name*") {           
     # move-item -path $File.fullname -Destination $cible -whatif  -verbose
        $total_archd ++
    }
    Else {
        $total_ACE ++
    }
}
write-host "total des fichiers reclassés dans News : $total_archd"
write-host "total des fichiers ACE dans People : $total_ACE"

(...) # closing procedures and display errors and standard output


I think I miss something related to single and double quotes ... or I'm totally wrong in that scripting.

What do you think about?

Phil Harvey

TLDR;

You need one argument per line.  The -if option has an argument that needs to go on a separate line.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

maxppp

Thanks Phil!
The script works well now ... however it seems that the condition is still case-sensitive, despite the "i".

Indeed, among the 1000 test files, 80 correspond to the condition but are not detected:
Quote
total files moved to News: 0 (i.e. $total_archd)
total ACE files in People: 1000 (i.e. $total_ACE)

???

Phil Harvey

Can you paste the exact condition that you used?  Are you sure you don't have any extra quotation marks?

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Your if command should look like this in the arg file
-if
$IPTC:Category =~ /(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i


While I don't understand powershell script, it seems to me you're overscripting (see Common Mistake #3).  Unless there's something else happening, the entire script can be replaced with a single exiftool command:
exiftool.exe -if '$IPTC:Category =~ "/(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i"' "-Directory=$Cible" $Source

Let exiftool do all the heavy work and parse the exiftool results if you want to display how many files are moved.
"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

maxppp

Bonsoir,

Sorry for the delay, I was off for a few days.

Phil, I dug the question of quotation marks in Powershell and discovered that I could switch from the argfile to the here-string rule, and the use of backtick character (`)(ASCII 96), which is the PowerShell escape character to prevent the substitution of a variable value in  string.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-6&viewFallbackFrom=powershell-Microsoft.PowerShell.Core

So, now my code looks like:
(...)
Foreach ($Fichier in $ListeFichiers) {
## here_string following and backtick to escape $IPTC:Category
    $ArgList = @"
    -if
    `$IPTC:Category =~ /clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea/i
    -filename
    $($File.FullName)
"@ ## no space allowed before closing "@
## end of here-string
    # send exiftool the command to execute
    $exiftoolproc.StandardInput.WriteLine("$ArgList`n-execute`n")     
}
(...)


It works fine. I get the result in an array that I filter to process the seeked files.
I processed my test-files (1,000) in 1min 13s and found the 80 target-files
So, thanks again Phil!

maxppp

Quote from: StarGeek on October 11, 2018, 12:32:20 PM
While I don't understand powershell script, it seems to me you're overscripting (see Common Mistake #3).  Unless there's something else happening, the entire script can be replaced with a single exiftool command:
exiftool.exe -if '$IPTC:Category =~ "/(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i"' "-Directory=$Cible" $Source

Let exiftool do all the heavy work and parse the exiftool results if you want to display how many files are moved.

Thanks StarGeek but I've tried that before and it's the reason why I looked for the stay_open feature.
The following code takes 25min 08sec to do the job.

Foreach ($Fichier in $ListeFichiers) {     
  If (( C:\Users\Administrateur\Documents\mes_scripts\EXIFtool\exiftool.exe -if '$IPTC:Category =~ "/(clj|dis|fin|ebf|edu|env|hth|lab|pol|rel|sci|soc|soi|war|wea)/i"' -filename $($File.FullName)) -like "File name*") {
      ## above, "File name" is part of the string returned when the condition is fulfilled
      # move-item -path $Fichier .fullname -Destination $cible
      $total_archd ++ # for count testing
  }
  Else {
      $total_ACE ++  # for count testing
  }
}

Phil Harvey

I think StarGeek's suggestion was to avoid the loop in the script, and call exiftool only once with $Source representing a list of ALL files to be tested (either by specifying a directory name, or a list of file names via the -@ option if you are specifying files individually).  This should be at least as fast, and maybe a bit faster, than what you are doing now.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Exactly that.

Use the command by itself, replacing $Cible and $Source with the actual directories.  As far as I can tell the only thing you're doing is checking the IPTC:Category for a match and moving it.  Let exiftool process the source directory (add the -r option to recurse if necessary) and the command, by itself, should take seconds.
"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

maxppp

Well done!

ExifTool is just a monstrously awesome tool!
Praised be Phil!

Thx StarGeek!