/* ****************************************************************************** @SriptName: App launcher.xys @Author: IT Services & Consulting Ulf Kohlmorgen @Created on: 2015-10-15 13:20:49 @Last modified: 2018-07-19 20:56:47 @Function: Find and lauch applications (from a filterable window) @Current version: v0.9 ****************************************************************************** */ end compare(, "19.00.0302", "v") == -1, "This script requires at least v19.00.0302, terminating now!"; $curVer = gettoken(regexmatches(readfile(self("file")), "^@Current version: v[0-9.]+"), 2, ": v"); $iniFile = self("path") . "\" . self("base") . ".ini"; $argsFile = self("path") . "\" . self("base") . "_CLI.txt"; $iniContent = <<<>>> [General] Version=$curVer Window_Width=400 Window_Height=700 Remove_Lnk_Extension=1 Remove_Exe_Extension=1 Default_Extensions=exe;lnk Use_Separators=1 Separator_Above=1 Separator_String=---------- [#SectionName#] ---------- Separator_Icon=:blank Ask_For_Args=1 Detect_Args_Via=file Args_Keyword=[cli] Edit_Mode_Key_Combo=1 ; Paths = Single or multiple paths, must be separated by "|" ; Recursive = -1: No recursion. 0: No recursion limit. Equal or larger than 1: Limit to that depth ; Extensions = Single or multiple extensions, separated by ";" or "|". "*." will be auto-affixed if missing ; Excluded_Paths = Single or multiple paths, separated by "|". No automatic wildcard embracing! ; Excluded_Files = Single or multiple files, separated by "|". No automatic wildcard embracing! ; Excluded files will be REMOVED from all other found files! ; Included_Files = Single or multiple files, separated by "|". No automatic wildcard embracing! ; ONLY these files will be displayed (minus Excluded_Files)! ; Section names = Only use the letters [a-zA-Z0-9] and/or "_", "-"! ; The order of the sections (apart from "General") matters! [Windows] Paths=%WINDIR% Recursive=-1 Extensions=exe Excluded_Files=bfsvc.exe ;[System32] ;Paths=%WINDIR%\System32 ;Recursive=-1 ;Extensions=exe ;Excluded_Paths=\wbem|\oobe ;Excluded_Files=dxdiag.exe|eventvwr.exe ;Included_Files=calc.exe|cleanmgr.exe|cmd.exe|control.exe|dxdiag.exe|eventvwr.exe|msinfo32.exe|mspaint.exe|notepad.exe|perfmon.exe ;[Tools] ;Paths=D:\Tools\@Shortcuts ;Recursive=-1 ;Extensions=*.lnk ;[User_Tools] ;Paths=D:\Users\%USERNAME%\Tools\@Shortcuts ;Recursive=-1 ;Extensions=*.lnk >>>; if (exists($iniFile) != 1) { writefile($iniFile, $iniContent, , "tu"); } if (exists($argsFile) != 1) { writefile($argsFile, "", , "utf8"); } $sections = formatlist(getsectionlist(, $iniFile), "f", , "!General"); $version = getkey("Version", "General", $iniFile); $windowWidth = getkey("Window_Width", "General", $iniFile); $windowHeight = getkey("Window_Height", "General", $iniFile); $removeLnkExtension = getkey("Remove_Lnk_Extension", "General", $iniFile); $removeExeExtension = getkey("Remove_Exe_Extension", "General", $iniFile); $defaultExtensions = getkey("Default_Extensions", "General", $iniFile); $useSeparators = getkey("Use_Separators", "General", $iniFile); $separatorAbove = getkey("Separator_Above", "General", $iniFile); $separatorString = getkey("Separator_String", "General", $iniFile); $separatorIcon = getkey("Separator_Icon", "General", $iniFile); // Version check $curVerIsNewer = (compare($curVer, $version, "v") == 1) ? true : false; if ($curVerIsNewer) { setkey $curVer, "Version", "General", $iniFile; // .ini upgrades if ($version == "" || $version < "0.5") { setkey "1", "Ask_For_Args", "General", $iniFile; setkey "file", "Detect_Args_Via", "General", $iniFile; setkey "[cli]", "Args_Keyword", "General", $iniFile; } if ($version < "0.6") { $content = readfile($iniFile); $find = <<<>>> ; Recursive = Empty or 0: No recursion; Anything else: Recursive >>>; $replace = <<<>>> ; Recursive = Empty or 0: No recursion; Larger than 0: Limit to that depth. "u" = unlimited recursion >>>; if (regexmatches($content, $find)) { $content = regexreplace($content, $find, $replace); writefile($iniFile, $content, , "tu"); } } if ($version < "0.7") { $content = readfile($iniFile); $find = <<<>>> ; Recursive = Empty or 0: No recursion; Larger than 0: Limit to that depth. "u" = unlimited recursion >>>; $replace = <<<>>> ; Recursive = -1: No recursion. 0: No recursion limit. Equal or larger than 1: Limit to that depth >>>; $content = regexreplace($content, $find, $replace); $content = regexreplace($content, "^Recursive=0", "Recursive=-1"); $content = regexreplace($content, "^Recursive=u", "Recursive=0"); writefile($iniFile, $content, , "tu"); } if ($version < "0.9") { // Default value: 1 = Shift setkey "1", "Edit_Mode_Key_Combo", "General", $iniFile; } } $askForArgs = getkey("Ask_For_Args", "General", $iniFile); $detectArgsVia = getkey("Detect_Args_Via", "General", $iniFile); $argsKeyword = getkey("Args_Keyword", "General", $iniFile); $editModeKeyCombo = getkey("Edit_Mode_Key_Combo", "General", $iniFile); // Default values if necessary $windowWidth = ($windowWidth) ? $windowWidth : 400; $windowHeight = ($windowHeight) ? $windowHeight : 700; $defaultExtensions = ($defaultExtensions) ? $defaultExtensions : "*.exe;*.lnk"; $separatorIcon = ($separatorIcon) ? $separatorIcon : ":queue"; $separatorString = ($separatorString) ? "$separatorString||$separatorIcon" : strrepeat("-", 50) . "^||$separatorIcon"; $separator = ($useSeparators) ? . $separatorString . : ; $detectArgsVia = (regexmatches($detectArgsVia, "(file|name|tag)")) ? $detectArgsVia : "file"; $argsKeyword = ($argsKeyword != "") ? $argsKeyword : "[cli]"; $editModeKeyCombo = (regexmatches($editModeKeyCombo, "[0-7]")) ? $editModeKeyCombo : 1; // Section edit mode // Modifier keys: 1 = Shift, 2 = Ctrl, 3 = Ctrl + Shift, 4 = Alt, 5 = Shift + Alt, 6 = Ctrl + Alt, 7 = Ctrl + Shift + Alt if (get("Shift") == $editModeKeyCombo) { // Try to find the current path in all sections $sectionMatch = false; foreach($section, $sections, , "e") { $paths = eval(quote(getkey("Paths", $section, $iniFile))); foreach($path, $paths, , "e") { // We have a match if (strpos(, $path) != -1) { $sectionMatch = true; // Either copy the filename or the last part of the path with a leading backslash to the clipboard if (exists() == 1) { copytext gpc(, "file"); } elseif (exists() == 2) { copytext "\" . gpc(, "component", -1); } // Edit the section $oldSectionContent = getsectionlist($section, $iniFile); if (!regexmatches($oldSectionContent, "^;?Recursive=")) { $oldSectionContent .= ";Recursive=-1"; } if (!regexmatches($oldSectionContent, "^;?Extensions=")) { $oldSectionContent .= ";Extensions=exe"; } if (!regexmatches($oldSectionContent, "^;?Excluded_Paths=")) { $oldSectionContent .= ";Excluded_Paths="; } if (!regexmatches($oldSectionContent, "^;?Excluded_Files=")) { $oldSectionContent .= ";Excluded_Files="; } if (!regexmatches($oldSectionContent, "^;?Included_Files=")) { $oldSectionContent .= ";Included_Files="; } $newSectionContent = input("Section: [$section]", , $oldSectionContent, "w", , 600); // Write section foreach($line, $newSectionContent, , "e") { $key = gettoken($line, 1, "="); $val = gettoken($line, 2, "=", , 2); setkey $val, $key, $section, $iniFile; } break 2; } } } // No matching section found if (!$sectionMatch) { $curPath = ; $sectionName = "New_section_name"; $newSectionContent = <<<>>> [$sectionName] Paths=$curPath ;Recursive=-1 ;Extensions=exe ;Excluded_Paths= ;Excluded_Files= ;Included_Files= >>>; $newSectionContent = input("Do not forget to change the section name!", , $newSectionContent, "w", , 600); $sectionName = regexreplace(regexmatches($newSectionContent, "^\[.+?\]"), "(\[|\])"); foreach($line, $newSectionContent, , "e") { if !(regexmatches($line, "^\[")) { $key = gettoken($line, 1, "="); $val = gettoken($line, 2, "=", , 2); setkey $val, $key, $sectionName, $iniFile; } } } } // Build menu $found = ""; foreach($section, $sections, , "e") { $paths = eval(quote(getkey("Paths", $section, $iniFile))); $recursive = getkey("Recursive", $section, $iniFile); $extensions = getkey("Extensions", $section, $iniFile); $excPaths = eval(quote(getkey("Excluded_Paths", $section, $iniFile))); $excFiles = getkey("Excluded_Files", $section, $iniFile); $incFiles = eval(quote(getkey("Included_Files", $section, $iniFile))); // Non-recursive by default if ($recursive == -1) { $recursive = "/n"; } elseif ($recursive == 0) { $recursive = ""; } elseif (regexmatches($recursive, "[0-9]+")) { $recursive = "/maxdepth=$recursive"; } else { $recursive = "/n"; } // Handle extensions incl. auto-wildcarding $extensions = ($extensions) ? $extensions : $defaultExtensions; if (strpos($extensions, "*") == -1) { $extensions = trim(regexreplace($extensions, "^|(;|\|)", ";*."), ";"); } // Check multi-location path(s) existence $multiPaths = ""; foreach($path, $paths, "|", "e") { if (exists($path) == 2) { $multiPaths .= ($multiPaths ? "|" . $path : $path); } } // Set exclude flags $excPathsFlag = ($excPaths) ? " /excl=$excPaths" : " "; $excFilesFlag = ($excFiles) ? " /exclfile=$excFiles" : " "; // Find item(s) $items = quicksearch("$extensions $recursive" . $excPathsFlag . $excFilesFlag, $multiPaths, , "s"); // Include file(s) - Only these items will be listed if ($incFiles) { $tmpItems = ""; foreach($incFile, $incFiles, , "e") { // The separator between file and its icon is "<:>" $file = gettoken($incFile, 1, "<:>", "t"); $icon = gettoken($incFile, 2, "<:>", "t"); // Is the file to be included in the list of found file(s)? if (strpos($items, $file) == -1) { continue; } // We need to get the path for the file from $items (first match!) $path = gettoken(regexmatches($items, "^.+\\" . regexreplace($file, "([\\.+(){\[^$])", "\$1")), 1, "|"); // Build "Caption|Data|Icon" if ($icon) { $tmpItems .= "$file|$path|$icon"; } else { $tmpItems .= "$file|$path|$path"; } } $items = formatlist($tmpItems, "e", ); // No file(s) to include (only), build "Caption|Data|Icon" normally } else { $items = regexreplace($items, "^([a-z\\].+\\)(.*?)(?=\r?\n|$)", "$2|$1$2|$1$2"); } // Build the entry list if ($items) { if ($separatorAbove) { $found .= ((strpos($separatorString, "#SectionName#") != -1) ? replace($separator, "#SectionName#", $section) : $separator) . $items; } else { $found .= $items . ((strpos($separatorString, "#SectionName#") != -1) ? replace($separator, "#SectionName#", $section) : $separator); } } } $found = formatlist($found, "e", ); if (!$found) { status "No items found, aborted!", "8B4513", "stop"; end true; } // Remove .lnk in captions if ($removeLnkExtension) { $found = regexreplace($found, "^(.+?)(\.lnk)\|", "$1|"); } if ($removeExeExtension) { $found = regexreplace($found, "^(.+?)(\.exe)\|", "$1|"); } // Selection window $selected = inputselect("", $found, , 1+32+64+1024, , $windowWidth, $windowHeight); $keyModifiers = get("Shift"); if ($selected == "") { status "No valid entry selected, aborted!", "8B4513", "stop"; end true; } // Only process arguments if neither "Alt" or "Ctrl+Shift+Alt" is pressed $args = ""; if ($askForArgs && $keyModifiers != 4 && $keyModifiers != 7) { if ($detectArgsVia LikeI "file") { $argsFileContent = readfile($argsFile); $found = regexmatches($argsFileContent, "^" . regexreplace($selected, "([\\.+(){\[^$])", "\$1") . "=.*?(?=\r?\n|$)"); if ($found) { $args = input("Enter arguments...", 2:=eval(gettoken($found, 2, "=", , 2)), 3:="w", 4:="", 5:=600); } } else { if (($detectArgsVia LikeI "name" && strpos($selected, $argsKeyword) != -1) || ($detectArgsVia LikeI "tag" && strpos(tagitems("tag", , $selected), $argsKeyword) != -1)) { $args = input("Enter arguments...", 3:="w", 4:="", 5:=600); } } } // Execute with / without admin permissions $vbsFile = "%TEMP%\~OpenElevatedCMD.vbs"; $vbsContent = <<<>>> Set UAC = CreateObject("Shell.Application") UAC.ShellExecute "$selected", $args, "", "runas", 1 >>>; if ($keyModifiers == 3 || $keyModifiers == 7) { writefile($vbsFile, regexreplace($vbsContent, "^[ \t]+"), , "utf8"); run """cscript"" ""$vbsFile"" //nologo", , 0, 0; } else { if ($args) { run """$selected"" $args"; } else { open $selected; } } if (exists($vbsFile) == 1) { delete 0, 0, $vbsFile; } /* @Changelog: +++ major new feature + new feature * changed feature - removed feature % improved performance ! fixed minor bug !!! fixed major bug v0.9 + Added a new option "Edit_Mode_Key_Combo=". The default is "1" = Shift key. Possible values are: 1 = Shift, 2 = Ctrl, 3 = Ctrl + Shift, 4 = Alt, 5 = Shift + Alt, 6 = Ctrl + Alt, 7 = Ctrl + Shift + Alt When this key / key combination is held when the script is invoked, it goes into an "edit mode". It checks all "Paths=" values from all sections to decide if one of them is in (or a subfolder of) the current path. In that case it copies the current selected file or folder (for folders: the last part with a prefixed backslash) into the clipboard opens an input window where you can paste it into the relevant key=value part. The "OK" button saves the new content for that section. If no value from "Paths=" matches it will show all entries for a new section in an edit window with the current path already inserted for "Paths=" v0.8 + Fron now on you can suppress the usage of arguments by holding the "alt" key modifier (for items that you do not want to execute with admin permissions) or "ctrl+shift+alt" keys (for items that need admin permissions). For example you have an entry in the "App launcher_CLI.txt" file like: C:\Windows\notepad.exe="""""", every time you execute the "notepad" entry, it would open this file as well. But if you just need "notepad" alone you can just use "alt" / "ctrl+ shift+alt" to get the desired behavior + "Included_Files=" in a section now supports the definition of a custom icon for an entry. The separator between the file name and the icon is bound to "<:>"! Internal XY icons are supported as well. An example: [God_Mode] Paths=C:\Windows Included_Files=explorer.exe<:>\Computer.ico v0.7 * "Recursive=" feature changed (again)! All values larger than 0 mean: Limit recursion to that scan depth (note: this was NOT changed). From now on, "0" will NOT turn off recursion (as in <= 0.6) but set recursion to on with NO limit to the recursion depth. -1 is now the internal default (if not defined in a section) and acts as the "NO recursion" switch. Changes to the .ini file should be handled automatically once you upgrade to v0.7... v0.6 + When "Ctrl + Shift" is hold while using the left mouse button to click the "OK" button the selected entry is started with admin permissions * "Recursive=" feature changed. All values larger than 0 mean: Limit recursion to that depth. The character "u" (for "u"nlimited) can be used to impose no limit to the recursion depth. "0" (NO recursion) is still the internal default value unless specified otherwise for a section entry v0.5 + Added three new settings in the "General" section: "Ask_For_Args=". Default = 1 "Detect_Args_Via=". Options = "file/name/tag". Default = "file" "Args_Keyword=". Default = "[cli]" These default settings allow it to execute command line apps with arguments If "Detect_Args_Via" is set to "name", the script will look for "" in the name of the file. If set to "tag", it will query the XY tag database to see if the file is tagged with "". Both options do NOT allow to set default arguments! The last option is "file". If the file ".\"' in the input field for the command line arguments C:\Windows\notepad.exe="""C:\Windows\System32\drivers\etc\hosts""" ; This would display the argument "C:\Windows\System32\drivers\etc\hosts" A note on these quoting rules: If a parameter which needs double quotes comes directly after the "=" it needs to be TRIPLE double quoted! If it comes later (as in the first example) it only needs single double quotes v0.4 ! Fixed a bug regarding the wrong spelling of "separator" Existing .ini files need a manual replacement of "Seperator_Icon=" with "Separator_Icon="! ! Fixed a regex bug reguarding the building of the "Caption|Data|Icon" stuff * Changed the default value of "Separator_Icon=" to ":blank" which will lead to an empty icon v0.3 + Added "Remove_Exe_Extension=" setting. Default = 1 * Changed default value for "Separator_String=" to: "---------- [#SectionName#] ----------" "#SectionName#" will be replaced with the belonging .ini section name... + Added "Separator_Above=" setting. Default = 1. When using 0, the separator lines come after the entries v0.2 ! Eval() was necessary to resolve environment variables from inside the .ini file v0.1 • Initial release */