Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for listprogs.cs

(view source code of listprogs.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Management;
  4. using System.Text.RegularExpressions;
  5. using Microsoft.Win32;
  6.  
  7.  
  8. namespace RobvanderWoude
  9. {
  10. 	class ListProgs
  11. 	{
  12. 		static string progver = "1.03";
  13.  
  14. 		static SortedList<string, string[]> reglist = new SortedList<string, string[]>( );
  15. 		static string pattern = String.Empty;
  16.  
  17. 		static int Main( string[] args )
  18. 		{
  19. 			#region Initialize Variables
  20.  
  21. 			string display = "List";
  22. 			bool separators = false;
  23. 			int rc = 0;
  24. 			int switchcount = 0;
  25.  
  26. 			#endregion Initialize Variables
  27.  
  28. 			#region Command Line parsing
  29.  
  30. 			if ( args.Length > 2 )
  31. 			{
  32. 				return ErrorMessage( "Too many command line arguments" );
  33. 			}
  34.  
  35. 			foreach ( string arg in args )
  36. 			{
  37. 				switch ( arg.ToUpper( ) )
  38. 				{
  39. 					case "/?":
  40. 						return ErrorMessage( );
  41. 					case "/A":
  42. 						if ( switchcount > 0 )
  43. 						{
  44. 							return ErrorMessage( "Invalid command line argument(s)" );
  45. 						}
  46. 						display = "Aligned";
  47. 						switchcount += 1;
  48. 						break;
  49. 					case "/S":
  50. 						if ( switchcount > 0 )
  51. 						{
  52. 							return ErrorMessage( "Invalid command line argument(s)" );
  53. 						}
  54. 						display = "Aligned";
  55. 						separators = true;
  56. 						switchcount += 1;
  57. 						break;
  58. 					case "/T":
  59. 						if ( switchcount > 0 )
  60. 						{
  61. 							return ErrorMessage( "Invalid command line argument(s)" );
  62. 						}
  63. 						display = "TabDelimited";
  64. 						switchcount += 1;
  65. 						break;
  66. 					default:
  67. 						if ( String.IsNullOrEmpty( pattern ) && VerifyRegExPattern( arg ) )
  68. 						{
  69. 							pattern = arg;
  70. 						}
  71. 						else
  72. 						{
  73. 							return ErrorMessage( "Invalid command line argument \"{0}\"", arg );
  74. 						}
  75. 						break;
  76. 				}
  77. 			}
  78.  
  79. 			if ( args.Length - switchcount > 1 )
  80. 			{
  81. 				return ErrorMessage( "Invalid command line argument(s)" );
  82. 			}
  83.  
  84. 			#endregion Command Line parsing
  85.  
  86. 			#region Read Registry
  87.  
  88. 			// Check 32-bit software on 32-bit OS or 64-bit software on 64-bit OS
  89. 			bool listreg = ListReg( "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall" );
  90. 			// Check 32-bit software on 64-bit OS
  91. 			if ( Is64bitOS( ) )
  92. 			{
  93. 				bool listreg2 = ListReg( "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" );
  94. 				listreg = listreg || listreg2;
  95. 			}
  96. 			if ( !listreg )
  97. 			{
  98. 				return ErrorMessage( "Error reading the registry.\n\tMake sure you have sufficient permissions to read the registry." );
  99. 			}
  100.  
  101. 			#endregion Read Registry
  102.  
  103. 			#region Show Results
  104.  
  105. 			switch ( display )
  106. 			{
  107. 				case "Aligned":
  108. 					rc = ShowTable( separators );
  109. 					break;
  110. 				case "TabDelimited":
  111. 					rc = ShowTabDelimited( );
  112. 					break;
  113. 				default:
  114. 					rc = ShowList( );
  115. 					break;
  116. 			}
  117.  
  118. 			#endregion Show Results
  119.  
  120. 			return rc;
  121. 		}
  122.  
  123. 		#region Subroutines
  124.  
  125. 		static int ErrorMessage( params string[] errmsg )
  126. 		{
  127. 			/*
  128. 			ListProgs.exe,  Version 1.03
  129. 			List "all" installed program names and versions found in the registry
  130.  
  131. 			Usage:  LISTPROGS  [ "pattern" ]  [ /A | /S | /T ]
  132.  
  133. 			Where:  "pattern"  limits output to DisplayName values matching the regular
  134. 							   expression "pattern"                  (case insensitive)
  135. 					/A         shows results in Aligned table           (default: List)
  136. 					/S         aligned table with Separator lines       (default: List)
  137. 					/T         shows results Tab delimited              (default: List)
  138.  
  139. 			Notes:  Searches HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall and
  140. 					HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
  141. 					for subkeys that have both DisplayName and DisplayVersion set.
  142. 					Registry keys are displayed in the default List output, but not in
  143. 					Aligned output nor in Tab delimited output.
  144. 					With Aligned output (/A) a window width of 110 columns or wider
  145. 					is recommended - may be set with the command:  MODE CON COLS=110
  146.  
  147. 			Written by Rob van der Woude
  148. 			http://www.robvanderwoude.com
  149. 			*/
  150.  
  151. 			if ( errmsg.Length > 0 )
  152. 			{
  153. 				List<string> errargs = new List<string>( errmsg );
  154. 				errargs.RemoveAt( 0 );
  155. 				Console.Error.WriteLine( );
  156. 				Console.ForegroundColor = ConsoleColor.Red;
  157. 				Console.Error.Write( "ERROR:\t" );
  158. 				Console.ForegroundColor = ConsoleColor.White;
  159. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  160. 				Console.ResetColor( );
  161.  
  162. 			}
  163.  
  164. 			Console.Error.WriteLine( );
  165.  
  166. 			Console.Error.WriteLine( "ListProgs.exe,  Version {0}", progver );
  167.  
  168. 			Console.Error.WriteLine( "List \"all\" installed program names and versions found in the registry" );
  169.  
  170. 			Console.Error.WriteLine( );
  171.  
  172. 			Console.Error.Write( "Usage:  " );
  173. 			Console.ForegroundColor = ConsoleColor.White;
  174. 			Console.Error.WriteLine( "ListProgs  [ \"pattern\" ]  [ /A | /S | /T ]" );
  175. 			Console.ResetColor( );
  176.  
  177. 			Console.Error.WriteLine( );
  178.  
  179. 			Console.Error.Write( "Where:  " );
  180. 			Console.ForegroundColor = ConsoleColor.White;
  181. 			Console.Error.Write( "\"pattern\"" );
  182. 			Console.ResetColor( );
  183. 			Console.Error.WriteLine( "  limits output to DisplayName values matching the regular" );
  184.  
  185. 			Console.Error.Write( "                   expression " );
  186. 			Console.ForegroundColor = ConsoleColor.White;
  187. 			Console.Error.Write( "\"pattern\"" );
  188. 			Console.ResetColor( );
  189. 			Console.Error.WriteLine( "                  (case insensitive)" );
  190.  
  191. 			Console.ForegroundColor = ConsoleColor.White;
  192. 			Console.Error.Write( "        /A" );
  193. 			Console.ResetColor( );
  194. 			Console.Error.Write( "         shows results in " );
  195. 			Console.ForegroundColor = ConsoleColor.White;
  196. 			Console.Error.Write( "A" );
  197. 			Console.ResetColor( );
  198. 			Console.Error.WriteLine( "ligned table           (default: List)" );
  199.  
  200. 			Console.ForegroundColor = ConsoleColor.White;
  201. 			Console.Error.Write( "        /S" );
  202. 			Console.ResetColor( );
  203. 			Console.Error.Write( "         aligned table with " );
  204. 			Console.ForegroundColor = ConsoleColor.White;
  205. 			Console.Error.Write( "S" );
  206. 			Console.ResetColor( );
  207. 			Console.Error.WriteLine( "eparator lines       (default: List)" );
  208.  
  209. 			Console.ForegroundColor = ConsoleColor.White;
  210. 			Console.Error.Write( "        /T" );
  211. 			Console.ResetColor( );
  212. 			Console.Error.Write( "         shows results " );
  213. 			Console.ForegroundColor = ConsoleColor.White;
  214. 			Console.Error.Write( "T" );
  215. 			Console.ResetColor( );
  216. 			Console.Error.WriteLine( "ab delimited              (default: List)" );
  217.  
  218. 			Console.Error.WriteLine( );
  219.  
  220. 			Console.Error.WriteLine( @"Notes:  Searches HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall and" );
  221.  
  222. 			Console.Error.WriteLine( @"        HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" );
  223.  
  224. 			Console.Error.WriteLine( "        for subkeys that have both DisplayName and DisplayVersion set." );
  225.  
  226. 			Console.Error.WriteLine( "        Registry keys are displayed in the default List output, but not in" );
  227.  
  228. 			Console.ForegroundColor = ConsoleColor.White;
  229. 			Console.Error.Write( "        A" );
  230. 			Console.ResetColor( );
  231. 			Console.Error.Write( "ligned output nor in " );
  232. 			Console.ForegroundColor = ConsoleColor.White;
  233. 			Console.Error.Write( "T" );
  234. 			Console.ResetColor( );
  235. 			Console.Error.WriteLine( "ab delimited output." );
  236.  
  237. 			Console.Error.Write( "        With " );
  238. 			Console.ForegroundColor = ConsoleColor.White;
  239. 			Console.Error.Write( "A" );
  240. 			Console.ResetColor( );
  241. 			Console.Error.Write( "ligned output (" );
  242. 			Console.ForegroundColor = ConsoleColor.White;
  243. 			Console.Error.Write( "/A" );
  244. 			Console.ResetColor( );
  245. 			Console.Error.WriteLine( ") a window width of 110 columns or wider" );
  246.  
  247. 			Console.Error.Write( "        is recommended - may be set with the command:  " );
  248. 			Console.ForegroundColor = ConsoleColor.White;
  249. 			Console.Error.WriteLine( "MODE CON COLS=110" );
  250. 			Console.ResetColor( );
  251.  
  252. 			Console.Error.WriteLine( );
  253.  
  254. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  255.  
  256. 			Console.Error.WriteLine( "http://www.robvanderwoude.com" );
  257.  
  258. 			return 1;
  259. 		}
  260.  
  261. 		static bool Is64bitOS( )
  262. 		{
  263. 			UInt16 addresswidth = 0;
  264. 			ManagementObjectSearcher searcher = new ManagementObjectSearcher( "root\\CIMV2", "SELECT * FROM Win32_Processor" );
  265. 			foreach ( ManagementObject queryObj in searcher.Get( ) )
  266. 			{
  267. 				addresswidth = (UInt16) ( queryObj["AddressWidth"] );
  268. 			}
  269. 			return ( addresswidth == 64 );
  270. 		}
  271.  
  272. 		static bool ListReg( string regpath )
  273. 		{
  274. 			try
  275. 			{
  276. 				Regex regex = new Regex( pattern, RegexOptions.IgnoreCase );
  277. 				RegistryKey regkey = Registry.LocalMachine.OpenSubKey( regpath );
  278. 				foreach ( var regsubkey in regkey.GetSubKeyNames( ) )
  279. 				{
  280. 					RegistryKey subkey = regkey.OpenSubKey( regsubkey );
  281. 					try
  282. 					{
  283. 						string displayname = subkey.GetValue( "DisplayName" ).ToString( );
  284. 						if ( !String.IsNullOrEmpty( displayname ) )
  285. 						{
  286. 							if ( String.IsNullOrEmpty( pattern ) || regex.IsMatch( displayname ) )
  287. 							{
  288. 								string displayversion = subkey.GetValue( "DisplayVersion" ).ToString( );
  289. 								if ( !String.IsNullOrEmpty( displayversion ) )
  290. 								{
  291. 									// Chop DisplayVersion string at first occurence of linebreak or null character
  292. 									if ( displayversion.IndexOfAny( "\0\n\r".ToCharArray( ) ) > -1 )
  293. 									{
  294. 										displayversion = displayversion.Split( "\0\n\r".ToCharArray( ) )[0];
  295. 									}
  296. 									// Remove all but the version number
  297. 									string trimpattern = @"(?:\b|\s|^)(?:v\.?)?(\d+(?:\.\d+)+[a-z]?)(?:\b|\s|$)";
  298. 									Regex trimregex = new Regex( trimpattern, RegexOptions.IgnoreCase );
  299. 									if ( trimregex.IsMatch( displayversion ) )
  300. 									{
  301. 										displayversion = trimregex.Match( displayversion ).ToString( );
  302. 									}
  303. 									// Add the entry to the list, if it wasn't added before
  304. 									string[] progval = new string[] { displayversion, subkey.ToString( ) };
  305. 									if ( !reglist.ContainsKey( displayname ) )
  306. 									{
  307. 										reglist.Add( displayname, progval );
  308. 									}
  309. 								}
  310. 							}
  311. 						}
  312. 					}
  313. 					catch ( Exception )
  314. 					{
  315. 						// ignore
  316. 					}
  317. 					subkey.Close( );
  318. 				}
  319. 				regkey.Close( );
  320. 				return true;
  321. 			}
  322. 			catch ( Exception )
  323. 			{
  324. 				return false;
  325. 			}
  326.  
  327. 		}
  328.  
  329. 		static int ShowList( )
  330. 		{
  331. 			foreach ( KeyValuePair<string, string[]> prog in reglist )
  332. 			{
  333. 				Console.WriteLine( "Registry Key    = {0}", prog.Value[1] );
  334. 				Console.WriteLine( "Display Name    = {0}", prog.Key );
  335. 				Console.WriteLine( "Display Version = {0}", prog.Value[0] );
  336. 				Console.WriteLine( );
  337. 			}
  338. 			return 0;
  339. 		}
  340.  
  341. 		static int ShowTabDelimited( )
  342. 		{
  343. 			foreach ( KeyValuePair<string, string[]> prog in reglist )
  344. 			{
  345. 				Console.WriteLine( "{0}\t{1}", prog.Key, prog.Value[0] );
  346. 			}
  347. 			return 0;
  348. 		}
  349.  
  350. 		static int ShowTable( bool separators = false )
  351. 		{
  352. 			string separator;
  353. 			int maxnamelen = 0;
  354. 			int maxverlen = 0;
  355. 			int totalwidth = Console.WindowWidth;
  356.  
  357. 			if ( separators )
  358. 			{
  359. 				separator = new String( '-', totalwidth - 1 );
  360. 			}
  361. 			else
  362. 			{
  363. 				separator = String.Empty;
  364. 			}
  365.  
  366. 			foreach ( KeyValuePair<string, string[]> prog in reglist )
  367. 			{
  368. 				maxnamelen = Math.Max( maxnamelen, prog.Key.Length );
  369. 				maxverlen = Math.Max( maxverlen, prog.Value[0].Length );
  370. 			}
  371. 			int col2width = maxverlen + 2;
  372. 			int col1width = totalwidth - col2width - 3;
  373. 			foreach ( KeyValuePair<string, string[]> prog in reglist )
  374. 			{
  375. 				Console.Write( separator );
  376. 				string key = prog.Key;
  377. 				if ( key.Length > col1width )
  378. 				{
  379. 					key = key.Substring( 0, col1width - 2 ) + "...";
  380. 				}
  381. 				Console.WriteLine( " {0,-" + col1width + "}  {1," + col2width + "}", key, prog.Value[0] );
  382. 			}
  383. 			Console.Write( separator );
  384. 			return 0;
  385. 		}
  386.  
  387. 		static bool VerifyRegExPattern( string testpattern )
  388. 		{
  389. 			// Test validity of RegEx pattern
  390. 			// Based on http://stackoverflow.com/questions/218680/can-i-test-if-a-regex-is-valid-in-c-sharp-without-throwing-exception
  391. 			if ( String.IsNullOrWhiteSpace( testpattern ) )
  392. 			{
  393. 				return false;
  394. 			}
  395. 			try
  396. 			{
  397. 				Regex.Match( "", testpattern );
  398. 				return true;
  399. 			}
  400. 			catch ( ArgumentException )
  401. 			{
  402. 				return false;
  403. 			}
  404. 		}
  405.  
  406. 		#endregion Subroutines
  407. 	}
  408. }
  409.  

page last modified: 2024-04-16; loaded in 0.0136 seconds