Advertisement
mansz81

devcon.js

Mar 16th, 2022
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * Remove Non-present Devices using DevCon
  3.  * =======================================
  4.  *
  5.  * removedevices.js is a script to automatically remove all non-present (i.e.
  6.  * disconnected) devices from a Windows computer system.  This can often be
  7.  * useful to prevent misbehaving and/or unnecessary drivers from being loaded.
  8.  *
  9.  * WARNING
  10.  * -------
  11.  * This script will remove/uninstall devices from your computer system.
  12.  * Although several important types of devices have been excluded from the
  13.  * default removal process, the possibility of removing devices critical to
  14.  * the operation of your computer system still exists.  PLEASE double-check
  15.  * the list of devices which will be removed before pressing "Y" and PLEASE
  16.  * create a system backup if you are remotely concerned about making your
  17.  * system unbootable.
  18.  *
  19.  * Examples
  20.  * --------
  21.  *  - To remove all non-present devices (except legacy and software devices)
  22.  *    either double-click the script or invoke it from the command prompt
  23.  *    without options.
  24.  *
  25.  *  - To delete devices without confirmation, run
  26.  *
  27.  *         removedevices.js /noconfirm
  28.  *
  29.  *  - To see the output of DevCon as the script executes, run
  30.  *
  31.  *         removedevices.js /verbose
  32.  *
  33.  *  - To create a list of devices which would be removed, run
  34.  *
  35.  *         removedevices.js /outfile:devicelist.txt
  36.  *
  37.  *  - To delete all devices (device IDs) listed in a file, run
  38.  *
  39.  *         removedevices.js /infile:devicelist.txt
  40.  *
  41.  *
  42.  * Installation Instructions
  43.  * =========================
  44.  *
  45.  * This script requires that devcon.exe be available, either in the same
  46.  * directory as this script or in a directory included in the PATH environment
  47.  * variable.
  48.  *
  49.  * For Windows XP and earlier, devcon.exe can be downloaded from Microsoft as
  50.  * described in <http://support.microsoft.com/kb/311272>.
  51.  *
  52.  * For Windows Vista and later, a newer version of devcon.exe is required.
  53.  * It can be extracted from the Windows WDK as described in
  54.  * <http://social.technet.microsoft.com/wiki/contents/articles/how-to-obtain-the-current-version-of-device-console-utility-devcon-exe.aspx>.
  55.  *
  56.  *
  57.  * ChangeLog
  58.  * =========
  59.  *
  60.  * 2012-08-02  Ryan Pavlik <abiryan@ryand.net>
  61.  *
  62.  *     * removedevices.js: Default to not removing extra volume shadow copies
  63.  *
  64.  * 2011-08-30  Kevin Locke <klocke@digitalenginesoftware.com>
  65.  *
  66.  *     * *.*: Add typical package accoutrements (README, ChangeLog, etc)
  67.  *
  68.  * 2011-02-10  Kevin Locke <klocke@digitalenginesoftware.com>
  69.  *
  70.  *     * removedevices.js: Fix crash when relaunching with CScript
  71.  *     * removedevices.js: Add note about devcon version for Vista and later
  72.  *
  73.  * 2010-02-21  Kevin Locke <klocke@digitalenginesoftware.com>
  74.  *
  75.  *     * removedevices.js: Initial Release
  76.  *
  77.  *
  78.  * COPYING
  79.  * =======
  80.  *
  81.  * Copyright 2010-2011 Digital Engine Software, LLC
  82.  *
  83.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  84.  * of this software and associated documentation files (the "Software"), to deal
  85.  * in the Software without restriction, including without limitation the rights
  86.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  87.  * copies of the Software, and to permit persons to whom the Software is
  88.  * furnished to do so, subject to the following conditions:
  89.  *
  90.  * The above copyright notice and this permission notice shall be included in
  91.  * all copies or substantial portions of the Software.
  92.  *
  93.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  94.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  95.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  96.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  97.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  98.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  99.  * THE SOFTWARE.
  100.  */
  101.  
  102. var WShell = WScript.CreateObject("WScript.Shell");
  103.  
  104. var options = {
  105.     deleteall: { desc: "Delete all non-present devices (Dangerous)" },
  106.     deletelegacy: { desc: "Also delete legacy non-present devices (Dangerous)" },
  107.     deletesw: { desc: "Also delete software non-present devices (Dangerous)" },
  108.     deletevss: { desc: "Also delete volume shadow service non-present devices (potentially dangerous)" },
  109.     infile: { desc: "Remove devices listed in a file (same format as devcon output)",
  110.           has_arg: true },
  111.     help: { desc: "Print this help message" },
  112.     noconfirm: { desc: "Do not ask for confirmation before deleting devices" },
  113.     outfile: { desc: "Output list of devices which would be removed",
  114.            has_arg: true },
  115.     quiet: { desc: "Do not print any unnecessary messages" },
  116.     verbose: { desc: "Print extra diagnostic information as the program executes" },
  117.     "?": { desc: "Print this help message" }
  118. };
  119.  
  120. // Make sure we are running with CScript so user can see output
  121. if (!/cscript\.exe$/i.test(WScript.FullName)) {
  122.     var cmdline = "cscript.exe";
  123.     var args = WScript.Arguments;
  124.     cmdline += " \"" + WScript.ScriptFullName + "\"";
  125.     for (var i=0; i<args.length; ++i)
  126.     cmdline += " \"" + args(i) + "\"";
  127.  
  128.     WShell.Run(cmdline, 1, false);
  129.     WScript.Quit(0);
  130. }
  131.  
  132. // Array.filter (from ECMA-262 Edition 5)
  133. // Code from Mozilla Developer Center
  134. if (!Array.prototype.filter) {
  135.     Array.prototype.filter = function(fun /*, thisp*/) {
  136.         var len = this.length >>> 0;
  137.         if (typeof fun != "function")
  138.             throw new TypeError();
  139.  
  140.         var res = [];
  141.         var thisp = arguments[1];
  142.         for (var i = 0; i < len; i++) {
  143.             if (i in this) {
  144.                 var val = this[i]; // in case fun mutates this
  145.                 if (fun.call(thisp, val, i, this))
  146.                     res.push(val);
  147.             }
  148.         }
  149.  
  150.         return res;
  151.     };
  152. }
  153.  
  154. function assert(cond /*, msg */) {
  155.     if (cond)
  156.     return;
  157.  
  158.     var msg = arguments[1];
  159.     if (msg == null)
  160.     msg = "Assertion Failed";
  161.  
  162.     WScript.Echo("Internal Program Error: " + msg);
  163.     WScript.Quit(1);
  164. }
  165.  
  166. function combine_values(v1, v2) {
  167.     if (v1 == null) {
  168.     return v2;
  169.     } else if (v1 instanceof Array) {
  170.     v1.push(v2);
  171.     return v1;
  172.     } else {
  173.     return new Array(v1, v2);
  174.     }
  175. }
  176.  
  177. function get_options(options, args) {
  178.     var optvals = new Array();
  179.  
  180.     var optregex = /^(?:\/|--)([^:]+)(?:(?::|=)(.+))?/;
  181.     for (var i=0; i<args.length; ++i) {
  182.     var arg = args(i);  // Careful of the syntax... JScript...
  183.  
  184.     var argmatch = optregex.exec(arg);
  185.     if (argmatch == null) {
  186.         optvals.push(arg);
  187.         continue;
  188.     }
  189.  
  190.     argname = argmatch[1];
  191.     argval = argmatch[2];
  192.     if (argname in options) {
  193.         var option = options[argname];
  194.         var optval = optvals[argname];
  195.         if (option.has_arg && (argval || i<args.length-1)) {
  196.         if (argval)
  197.             optvals[argname] = combine_values(optval, argval);
  198.         else
  199.             // Careful again...
  200.             optvals[argname] = combine_values(optval, args(++i));
  201.         } else
  202.         optvals[argname] = combine_values(optval, true);
  203.     } else {
  204.         throw new Error("Unrecognized option: " + arg);
  205.     }
  206.     }
  207.  
  208.     return optvals;
  209. }
  210.  
  211. function get_nonpresent_devices() {
  212.     if (optvals["infile"])
  213.     try {
  214.         return read_devids(optvals["infile"]);
  215.     } catch (ex) {
  216.         WScript.Echo("Error:  Unable to read input file \"" +
  217.             optvals["infile"] + "\":  " + ex.message);
  218.         WScript.Quit(1);
  219.     }
  220.  
  221.     var deletelegacy = !!optvals["deletelegacy"];
  222.     var deletesw = !!optvals["deletesw"];
  223.     var deletevss = !!optvals["deletevss"];
  224.     if (optvals["deleteall"])
  225.     deletelegacy = deletesw = deletevss = true;
  226.  
  227.     var alloutput, presentoutput;
  228.     try {
  229.     alloutput = run_program("devcon.exe findall *").output
  230.     presentoutput = run_program("devcon.exe find *").output;
  231.     } catch (ex) {
  232.     WScript.Echo("Error:  Unable to execute devcon.exe:  " + ex.message);
  233.     WScript.Quit(1);
  234.     }
  235.  
  236.     var alldevices, presentdevices;
  237.     try {
  238.        alldevices = parse_devcon_output(alloutput);
  239.        presentdevices = parse_devcon_output(presentoutput);
  240.     } catch (ex) {
  241.     WScript.Echo("Error:  Unable to parse devcon output:  " + ex.message);
  242.     WScript.Quit(1);
  243.     }
  244.  
  245.     var nonpresentdevices = new Array(alldevices.length - presentdevices.length);
  246.     var ai = 0, ni = 0;
  247.     for (var pi=0; pi<presentdevices.length; ++ai, ++pi) {
  248.     var presentdevice = presentdevices[pi];
  249.  
  250.     while (alldevices[ai].devid < presentdevice.devid)
  251.         nonpresentdevices[ni++] = alldevices[ai++];
  252.     assert(alldevices[ai].devid == presentdevice.devid,
  253.         "Device listed in find but not in findall!?");
  254.     }
  255.     while (ai < alldevices.length)
  256.     nonpresentdevices[ni++] = alldevices[ai++];
  257.     assert(ni == nonpresentdevices.length, "All devices not accounted for");
  258.  
  259.     var htreere = /^HTREE\\/;
  260.     var legacyre = /^ROOT\\LEGACY_/;
  261.     var vssre = /^STORAGE\\VOLUMESNAPSHOT/;
  262.     var swre = /^SW(?:MUXBUS)?\\/;
  263.     nonpresentdevices = nonpresentdevices.filter(function(dev) {
  264.         // Note:  Boolean inverted for efficiency (only regex when needed)
  265.         return !((!deletelegacy && legacyre.test(dev.devid)) ||
  266.             (!deletesw && swre.test(dev.devid)) ||
  267.             (!deletevss && vssre.test(dev.devid)) ||
  268.             htreere.test(dev.devid));
  269.     });
  270.  
  271.     return nonpresentdevices;
  272. }
  273.  
  274. function parse_devcon_output(output) {
  275.     // Note:  Restrictions loosened so we can use it for reading input files
  276.     var devregex = /^(\S+)\s*(?::\s*(.*))?$/gm;
  277.     var devices = new Array();
  278.  
  279.     var match;
  280.     while ((match = devregex.exec(output)) != null)
  281.     devices.push({devid: match[1], devname: match[2]});
  282.  
  283.     devices.sort(function(a, b) {
  284.         if (a.devid < b.devid)
  285.         return -1;
  286.         else if (b.devid < a.devid)
  287.         return 1;
  288.         else
  289.         return 0;
  290.     });
  291.  
  292.     return devices;
  293. }
  294.  
  295. function print_help() {
  296.     WScript.StdOut.WriteLine("Device Removal Script\n" +
  297.         "Supported Options:");
  298.     for (var optname in options) {
  299.     var optnamelen = optname.length;
  300.     var padsize = 19 - optnamelen;
  301.     var padding = new Array(padsize > 0 ? padsize : 0).join(' ');
  302.     WScript.StdOut.WriteLine('/' + optname + padding + options[optname].desc);
  303.     }
  304. }
  305.  
  306. function read_devids(filename) {
  307.     var file;
  308.     if (filename == "-")
  309.     file = WScript.StdIn;
  310.     else {
  311.     var fso = new ActiveXObject("Scripting.FileSystemObject");
  312.     file = fso.OpenTextFile(filename, 1);
  313.     }
  314.  
  315.     var devices = parse_devcon_output(file.ReadAll());
  316.  
  317.     if (filename != "-")
  318.     file.Close();
  319.  
  320.     return devices;
  321. }
  322.  
  323. // Note:  I am not aware of a safe way to read stdout and stderr separately
  324. //        without risking a deadlock, unless the output can be predicted.
  325. //        So we read the combined output here...
  326. // See the discussion at http://www.tech-archive.net/Archive/Scripting/microsoft.public.scripting.wsh/2004-10/0287.html
  327. // for more details
  328. function run_program(cmd) {
  329.     var wsexec = WShell.Exec(cmd + " 2>&1");
  330.     wsexec.StdIn.Close();
  331.    
  332.     var output = "";
  333.     while (wsexec.Status == 0)
  334.     output += wsexec.StdOut.ReadAll();
  335.  
  336.     return { exitcode: wsexec.ExitCode, output: output };
  337. }
  338.  
  339. function write_devids(filename, devices) {
  340.     var file;
  341.     if (filename == "-")
  342.     file = WScript.StdOut;
  343.     else {
  344.     var fso = new ActiveXObject("Scripting.FileSystemObject");
  345.     file = fso.CreateTextFile(filename, true);
  346.     }
  347.  
  348.     for (var i=0; i<devices.length; ++i)
  349.     file.WriteLine(devices[i].devid);
  350.  
  351.     if (filename != "-")
  352.     file.Close();
  353. }
  354.  
  355. var optvals = get_options(options, WScript.Arguments);
  356.  
  357. if (("help" in optvals) || ("?" in optvals)) {
  358.     print_help();
  359.     WScript.Quit(0);
  360. }
  361.  
  362. var quiet = !!optvals["quiet"];
  363. var verbose = !!optvals["verbose"];
  364.  
  365. nonpresentdevices = get_nonpresent_devices();
  366.  
  367. if (optvals["outfile"]) {
  368.     try {
  369.     write_devids(optvals["outfile"], nonpresentdevices);
  370.     } catch (ex) {
  371.     WScript.Echo("Error:  Unable to write output file:  " + ex.message);
  372.     WScript.Quit(1);
  373.     }
  374.  
  375.     WScript.Quit(0);
  376. }
  377.  
  378. if (!optvals["noconfirm"]) {
  379.     WScript.StdOut.WriteLine("Devices which will be removed:");
  380.     for (var i=0; i<nonpresentdevices.length; ++i) {
  381.     var npd = nonpresentdevices[i];
  382.     WScript.StdOut.WriteLine(npd.devid)
  383.     if (npd.devname)
  384.         WScript.StdOut.WriteLine("\t" + npd.devname)
  385.     }
  386.  
  387.     WScript.StdOut.Write("Are you sure you want to REMOVE "+ nonpresentdevices.length + " Drivers (Y/N)? ");
  388.     var answer = WScript.StdIn.Read(1);
  389.     if (answer != "y" && answer != "Y")
  390.     WScript.Quit(0);
  391. }
  392.  
  393. for (var i=0; i<nonpresentdevices.length; ++i) {
  394.     var device = nonpresentdevices[i];
  395.     try {
  396.     if (!quiet)
  397.         WScript.StdOut.Write(
  398.             (i+1) + " Removing " + device.devid + ":\n");
  399.  
  400.     var result = run_program("devcon.exe remove \"@" + device.devid + "\"");
  401.  
  402.     if (verbose) {
  403.         WScript.StdOut.WriteLine(result.output);
  404.         WScript.StdOut.WriteLine(
  405.             "Removal finished exit code " + result.exitcode);
  406.     }
  407.     } catch (ex) {
  408.     WScript.StdOut.WriteLine("DevCon encountered an error: " + ex.message);
  409.     }
  410. }
  411.  
  412. if (!quiet)
  413.     WScript.StdOut.WriteLine("All Done");
  414.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement