Usage: ecfind [--server <host>] [--user <username>] [--pw <password>]
  general:
   --object <commander-object-type-name>
   [--query <query-expression> | @</property-path-or-expansion> | -]
   [--tz <timezone>]
   [--select <property>[,<property...]]
   [--sort <property>[,<property...]]
   [--maxIds <n>]
  actions:
   [--print id | xml | name | count]
   [--fail-if none | any]
   [--expandString <string>]...
   [--exec <command-or-script>]...
   [--setProperty <property>=<value>]...
   [--copyProperty <target>=<original>]...
   [--editProperty <property>=~s/<old>/<new>/[g]]...
   [--deleteProperty <property>]...
  debugging: [--debug]
  help: [--help [usage | query | about]]

Query Syntax:

  A query takes the form of a function call.  For example, the following query
will search for the project named "Default":

equals("projectName","Default")

  Certain functions ("and", "or", "not") take other functions as arguments,
allowing one to express complicated queries.  The following query will search
for all projects where the name contains "EC" and the property "ec-visibility"
is set to the value "all":

and(contains("projectName","EC"),equals("ec-visibility","all"))

Functions can be nested arbitrarily deeply.  Property names can refer to either
intrinsic properties, or properties added to the top-level of the object in
question (more specifically, one cannot search for properties contained in
property sheets on objects).  Both property names and values should be quoted
in a query.

Valid functions include:

    - logical operators -
            and ( <function()>, <function()>, ... )
             or ( <function()>, <function()>, ... )
            not ( <function()> )

    - comparison operators -
         equals ( "propertyName", "value" )
       notEqual ( "propertyName", "value" )
    greaterThan ( "propertyName", "value" )
 greaterOrEqual ( "propertyName", "value" )
       lessThan ( "propertyName", "value" )
    lessOrEqual ( "propertyName", "value" )

    - pattern matching operators -
           like ( "propertyName", "value" )
       contains ( "propertyName", "value" )
        notLike ( "propertyName", "value" )

    - existence testing operators -
      isNotNull ( "propertyName")
         isNull ( "propertyName")

    - range testing operators -
        between ( "propertyName", "lowerValue", "upperValue" )
  
Many of the operators have synonyms (for example, one can use "ge" instead
of "greaterOrEqual" to save typing).  However, use of the full operator
name is encouraged.

In order to facilitate queries involving dates, a special macro, "#date:",
can be used in place of the "value" in a query.  For example:

  "#date: 12 Dec 2001 8:45 AM EST"

One can also specify relative or sloppy dates:

  "#date: last week"
  "#date: last Monday"
  "#date: today"

Note: when specifying relative dates, especially "today", be aware of the
pitfalls caused by the fact that Commander performs the comparison based
on a specific full date/time.  The macro "#date: today" actually translates
to midnight at the beginning of the current day (which matches best to
the common intent).  In contrast, the macro "#date: yesterday" actually
translates to exactly 24 hours ago.  In general, try to use more complete
date/time specifications.

Note: date conversions require knowlege of the current timezone.  Due to
limitations in the version of perl, the utility may be unable to determine
your timezone.  If you get a message indicating this, you may need to
specify your timezone on the command line using the "--tz <timezone>"
option.  Please specify the timezone in the format "CST6CDT" or "EST".

More detail on each function can be found in the ElectricCommander online
help, under the help topic for the findObjects API.


Property References and Expansion:

Because query strings and actions can become quite unwieldy to pass in via
the command line (due to length as well as the need to protect strings and
quotes from the shell being used), alternate means to specify the query and
actions are provided.

If the query string is simple the dash character, the query is read from STDIN.

If the query string starts with the special character "@", the remainder of
the query string is specially processed.  If the remainder starts with the
forward slash ("/"), then it is taken to be a full property path, and the query
will be read from the specified property.  Otherwise, the remainder is passed
through "expandString" to expand all embedded property references (such as
$[/myUser/saved_property]).

Note that in all cases, a query can cross multiple lines, which can be helpful
in order to make complicated queries more legible.  (The ability to have the
query string span multiple lines when passed in on the command line will be
limited by the particular shell being used, which in practice means that one
would typically use this syntax when reading the query in from STDIN or from
a property.)

Certain actions also honor the "@" syntax, allowing one to store the details
of an editProperty action (for example) in a property.  The actions that permit
this form of property expansion include:

  --setProperty
  --copyProperty
  --editProperty
  --expandString
  --exec

Actions:

  Of course, it's not useful to search for things unless one wants to do
something with the results.

 --print id | xml | name | count

By default, the utility will simply print the ElectricCommander object IDs
for the objects found.  This is particularly useful when the query is being
run from a script that intends to perform other operations with the objects
found (most ectool commands have a syntax that accepts the object ID as a
valid way to identify the object).  This default is the same as specifying
"--print id" for the action.

For humans, often the object name is more useful.  Specifying "--print name"
will result in the object's name being displayed.  Note, however, that unlike
the object ID, the object name may not be sufficient to unambiguously identify
the object in question.  For example, it would be common to find many steps
named "setup" in any system with many procedures.

Another option, particularly useful with PowerShell, is to print the results
in the form of a complete XML document.  THe "--print xml" accomplishes this.

The "--print count" option simply prints an incrementing counter value for
each item.  This may be useful for determining relative position in a large
amount of output, but more commonly, one merely wants to know how many items
are found by the specified query.  The "--print total" option accomplishes
this goal.

 --fail-if none | any

Closely related to the "count" option are the the "--fail-if" options.  These
are intended for use in scripting where one merely needs to make a simple
binary decision based on the query results.  Specifying "--fail-if none"
causes the utility to return a failure error code (1) if there are no results
returned by the query.  The "--fail-if any" option results in a failure code
if there are any results returned.

The "--fail-if" option can be combined with other actions as required, although
doing so may make it difficult for the calling script to know the exact reason
for a failure exit code.

 --expandString <string>...

When it is desirable to have a little more control over the output, in some
cases the "--expandString" option may be useful.  The provided string is sent
to the "expandString" API in order to have all the embedded property
references (e.g. '$[description]') expanded prior to being displayed.  Note
that this option is often of limited use, since it attempts to expand nested
property references, which may not be valid outside of the job execution
context.  Clever use of embedded javascript references can mitigate this to
some extent, but in general this option should be used very carefully and only
when the content of the properties in question is well-understood and is
defined and valid outside of the job execution context.

 --exec <command-or-script>...

If one needs to perform more interesting work with each object that the query
locates, the "--exec" option can be used to execute an external script or
program for each object.  Multiple external scripts or programs can be
specified, if desired, and if so they are executed in the order specified on
the command line.

When the script or program executes, it can find selected bits of information
about the object in the environment variables.  Each object will at least
have the "ECFIND_objectId" variable set to the object ID that was returned by
the query.  Depending on the object type, additional "ECFIND_" variables may
be set.  More specifically, all intrinsics where the name ends in "Name" or
"Id", or where the name contains the string "container" will be placed into
the environment.  This should be sufficient for the executed script to
uniquely identify the object without needing to use the object ID.  For
example, a query for procedureStep objects will result in at least the
following environment variables being set to valid values:

  ECFIND_objectId
  ECFIND_projectName
  ECFIND_procedureName
  ECFIND_stepName

A common reason to execute an external script for each located object is
because one wishes to make changes -- which many times can be expressed in
terms of manipulating properties, either intrisic or custom.  In order to
facilitate this in as efficient a manner as possible, a set of "property"
operations can be specified:

 --setProperty <property>=<value>...

The "--setProperty" action permits one to set one or more properties on
each object found to a specific value.  As usual with setProperty operations,
if the property does not exist, it will be created.  Note that the property
in question can be a either an intrinsic property or a custom property.

 --copyProperty <target>=<original>...

The "--copyProperty" action permits one to copy the value of an existing
property to a target property.  If the target property exists, its value
will be replaced.  Only the value is copied (the description field is
ignored).  Note that the properties involved can be either intrinsic or
custom properties.

 --deleteProperty <property>...

If one can create properties, it stands to reason that one should be easily
able to remove properties.  The "--deleteProperty" action allows one to
delete custom properties.  It is not an error to attempt to delete a property
that does not exist, but you cannot delete an intrinsic property (use the
setProperty action to set the intrinsic's value to the empty string instead).

 --editProperty <property>=~s/<old>/<new>/[g]...

Finally, an advanced action is the "--editProperty" operation.  This action
functions like the "--setProperty" operation, except that it sets the new
value based on the application of a Perl regex substitution operation on the
original value (if the property did not originally exist on the object, its
value is taken to be the null string).  This functionality allows for global
search and replace operations to be performed.

Examples:

The following simple query prints a list of all of the projects:

ecfind --object project

The same, but this time print the project names:

ecfind --object project --print name

It might be nice to sort it, and make sure we print a LOT of them:

ecfind --object project --sort projectName --maxId 1000000 --print name

Limit the query to projects names that contain the string "EC":

ecfind --object project --query "contains('projectName','EC')" --print name

A more complicated query, that prints the names of projects where the name
contains the string "EC", and either the custom property "ec_visibility" does
not exist or has the value "all", and is not a plugin (i.e. the intrinsic
property "pluginName" does not exist). Use the maxId option to make sure we
search all projects, and sort the names. Line wrapping is for legibility:

ecfind --object property --maxId 1000000 --query
 "and(contains('projectName','EC'), 
      or(isNull('ec_visibility'),equals('ec_visibility','all'))
      isNull('pluginName'))" --sort projectName --print name

Find all projects that contain the string "EC" in the name, and print
out the full ElectricCommander path to the project:

ecfind --object project --query "contains('projectName','example')"
  --exec "echo /projects/%ECFIND_projectName%"

Finally, the following example is a query that finds all steps in any project
who's name ends in the string "lib" and where the command block (an intrinsic
property) contains the string "workdir".  For each step found, it will print
the unique object id of the step followed by the Commander path to the step
in question, make a backup copy of the command block, change the string
"workdir" in the command block to "working_directory", and finally write a
log message to the front of a custom property named "changeLog" on the step:

ecfind --object procedureStep --query
 "and(like('projectName','%lib'), contains('command','workdir'))"
 --print id
 --expandString
  "/projects/$[projectName]/procedures/$[procedureName]/steps/$[stepName]"
 --copyProperty "command_20120717=command"
 --editProperty "command=~s/workdir/working_directory/g"
 --editProperty "changeLog=~s/^/Bulk copy-replace to fix workdir name\n/"


ecfind version 0.4f