Skip to content

Instantly share code, notes, and snippets.

@pcrama
Created March 16, 2017 21:02
Show Gist options
  • Save pcrama/a6ff54f759e1cc3d0ba3503184416d6c to your computer and use it in GitHub Desktop.
Save pcrama/a6ff54f759e1cc3d0ba3503184416d6c to your computer and use it in GitHub Desktop.
Simplistic command line interface for Windows Search
using System.Data.OleDb;
using System;
class WDSCli
{
static void Main(string[] args)
{
int maxResults = 200; // Don't output more than this amount of results
bool help = args.Length == 0;
string searchRoot = ""; // limit scope of search
string likeQuery = "";
bool inQuery = false;
bool winPathSyntax = false;
bool verbose = false;
int i = 0;
while (i < args.Length) {
if (inQuery) {
likeQuery += ("" == likeQuery?"":"%") + args[i];
} else if ("-h" == args[i] || "--help" == args[i]) {
help = true;
} else if ("-w" == args[i] || "--win" == args[i]) {
winPathSyntax = true;
} else if ("-v" == args[i] || "--verbose" == args[i]) {
verbose = true;
} else if ("-r" == args[i] || "--root" == args[i]) {
searchRoot = args[++i];
} else if ("-m" == args[i] || "--max" == args[i]) {
maxResults = int.Parse(args[++i]);
} else if ("--" == args[i]) {
inQuery = true;
} else {
inQuery = true;
likeQuery = args[i];
}
++i;
}
if (help || "" == likeQuery) {
usage();
} else {
run(searchRoot, likeQuery, maxResults, winPathSyntax, verbose);
}
}
static void usage()
{
Console.Error.WriteLine(
"wdscli [--max 200] # -m: limit result count\n"
+ " [--root <search root>] # -r: set root of search\n"
+ " [--verbose] # -v\n"
+ " [--win] # -w: query fragments and output use \\ as directory separator\n"
+ " [--help] # -h: this help text\n"
+ " [--] <query fragments>"
+ "\n"
+ "Query Windows File Search\n"
+ "\n"
+ "The query fragments are matched against the full file's path (search root\n"
+ "included) each of the fragments must appear in the given order. There is\n"
+ "an issue where a fragment 388 doesn't match 3880 but I don't have a\n"
+ "workaround for that.\n"
+ "\n"
+ "Special characters can be used (see SQL LIKE operator's syntax)\n"
+ "_ matches any character. I don't know how to escape it.\n"
+ "[ab] macthes 'a' or 'b'. Ranges are allowed, too.\n"
+ "[^ab] anything but 'a' or 'b'\n"
+ "% matches anything. This is inserted between fragments automatically\n"
+ "^ (only special as first char of first fragment) first fragment must\n"
+ " match at the start of the full path name\n"
+ "$ (only special as last char of last fragment) first fragment must\n"
+ " match at the end of the full path name\n"
);
}
static void run(string searchRoot, string likeQuery, int maxResults, bool winPathSyntax, bool verbose)
{
if (!winPathSyntax) {
// translate unix path syntax to windows path syntax in query
likeQuery = likeQuery.Replace('/', '\\');
}
if (likeQuery.StartsWith("^")) {
likeQuery = likeQuery.Substring(1, likeQuery.Length - 1);
} else {
likeQuery = "%" + likeQuery;
}
if (likeQuery.EndsWith("$")) {
likeQuery = likeQuery.Substring(0, likeQuery.Length - 1);
} else {
likeQuery = likeQuery + "%";
}
/* I wanted to do this:
string query = @"SELECT System.ItemPathDisplay FROM SystemIndex WHERE " +
("" == searchRoot?"":@"scope = @searchRoot AND ") +
@"System.ItemPathDisplay LIKE @likeQuery";
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.AddWithValue("@searchRoot", searchRoot);
command.Parameters.AddWithValue("@likeQuery", likeQuery);
but I got this exception:
System.InvalidOperationException: The ICommandWithParameters interface is not supported by the 'Search.CollatorDSO' provider. Command parameters are unsupported with the current provider.
So I settled for this low-tech escaping mechanism: */
likeQuery = likeQuery.Replace("'", "''");
// MSDN suggests using ISearchCatalogManager::GetQueryHelper and its get_ConnectionString method
// but it didn't work for me
string connectionString = "Provider=Search.CollatorDSO;Extended Properties=\"Application=Windows\"";
OleDbConnection connection = new OleDbConnection(connectionString);
string query = @"SELECT TOP " + maxResults + @" System.ItemPathDisplay FROM SystemIndex " +
"WHERE " +
("" == searchRoot?"":@"scope ='file:" + searchRoot + "' AND ") +
@"System.ItemPathDisplay LIKE '" + likeQuery + "' " +
"AND NOT System.ItemName LIKE '%~' AND NOT System.ItemName LIKE '%#' " +
"ORDER BY System.ItemPathDisplay";
if (verbose) { Console.Error.WriteLine(query); }
OleDbCommand command = new OleDbCommand(query, connection);
connection.Open();
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read()) {
string row = reader.GetString(0);
Console.WriteLine(winPathSyntax?row:row.Replace('\\', '/'));
}
connection.Close();
}
}
/* Local Variables: */
/* mode: c */
/* compile-command: "c:/Windows/Microsoft.NET/Framework64/v4.0.30319/csc.exe wdscli.cs" */
/* End: */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment