├── .gitignore ├── AdvancedInstaller ├── .gitignore ├── wu10man.aip ├── wu10man.back (1).aip └── wu10man.back.aip ├── CreatePortable.ps1 ├── LICENSE ├── README.md ├── WereDev.Utils.Win32Wrappers ├── FileAccessBridge.cs ├── Models │ └── ServiceConfigInfo.cs ├── Properties │ └── AssemblyInfo.cs ├── WereDev.Utils.Win32Wrappers.csproj ├── WindowsApiBridge.cs └── WindowsServiceBridge.cs ├── WereDev.Utils.Wu10Man.Core ├── DependencyManager.cs ├── Enums │ ├── ServiceStartMode.cs │ └── WindowsApiPrivelegeNames.cs ├── Exceptions │ └── EntityNotFoundException.cs ├── Interfaces │ ├── IFileManager.cs │ ├── IHostsFileEditor.cs │ ├── ILogWriter.cs │ ├── IRegistryEditor.cs │ ├── IWindowsPackageManager.cs │ ├── IWindowsServiceManager.cs │ ├── IWindowsTaskManager.cs │ └── Providers │ │ ├── ICredentialsProvider.cs │ │ ├── IFileIoProvider.cs │ │ ├── IRegistryProvider.cs │ │ ├── IUserProvider.cs │ │ ├── IWindowsApiProvider.cs │ │ ├── IWindowsPackageProvider.cs │ │ ├── IWindowsServiceProvider.cs │ │ ├── IWindowsServiceProviderFactory.cs │ │ └── IWindowsTaskProvider.cs ├── Models │ ├── AppInfo.cs │ ├── AppInfoExtended.cs │ ├── DeclutterConfig.cs │ ├── PackageInfo.cs │ ├── SplitHostsFile.cs │ ├── WindowsTask.cs │ └── WindowsTaskConfig.cs ├── Properties │ └── AssemblyInfo.cs ├── Services │ ├── FileManager.cs │ ├── HostsFileEditor.cs │ ├── RegistryEditor.cs │ ├── WindowsPackageManager.cs │ ├── WindowsServiceManager.cs │ └── WindowsTaskManager.cs ├── WereDev.Utils.Wu10Man.Core.csproj ├── app.config └── packages.config ├── WereDev.Utils.Wu10Man.Providers ├── CredentialsProvider.cs ├── FileIoProvider.cs ├── PowerShellProvider.cs ├── Properties │ └── AssemblyInfo.cs ├── RegistryProvider.cs ├── UserProvider.cs ├── WereDev.Utils.Wu10Man.Providers.csproj ├── WindowsApiProvider.cs ├── WindowsServiceProvider.cs ├── WindowsServiceProviderFactory.cs ├── WindowsTaskProvider.cs ├── app.config └── packages.config ├── Wu10Man.sln ├── Wu10Man ├── App.xaml ├── App.xaml.cs ├── AppSettings.cs ├── Converters │ └── MathConverter.cs ├── CustomDictionary.xml ├── Properties │ └── AssemblyInfo.cs ├── Services │ ├── EnvironmentVersionHelper.cs │ └── Wu10Logger.cs ├── UserControls │ ├── DeclutterControl.xaml │ ├── DeclutterControl.xaml.cs │ ├── GroupPolicyControl.xaml │ ├── GroupPolicyControl.xaml.cs │ ├── HostsFileControl.xaml │ ├── HostsFileControl.xaml.cs │ ├── Models │ │ ├── DeclutterModel.cs │ │ ├── HostStatus.cs │ │ ├── HostsFileModel.cs │ │ ├── ModelBase.cs │ │ ├── PackageInfo.cs │ │ ├── PauseUpdatesModel.cs │ │ ├── ProgressBarModel.cs │ │ ├── WindowsServiceStatusModel.cs │ │ ├── WindowsServicesModel.cs │ │ ├── WindowsTasksModel.cs │ │ └── WindowsTasksStatusModel.cs │ ├── PauseUpdatesControl.xaml │ ├── PauseUpdatesControl.xaml.cs │ ├── ProgressBarControl.xaml │ ├── ProgressBarControl.xaml.cs │ ├── UserControlBase.cs │ ├── UserControlBaseWithWorker.cs │ ├── WindowsServicesControl.xaml │ ├── WindowsServicesControl.xaml.cs │ ├── WindowsTasksControl.xaml │ └── WindowsTasksControl.xaml.cs ├── UserWindows │ ├── About.xaml │ ├── About.xaml.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ └── Models │ │ ├── ITabItemModel.cs │ │ ├── MainWindowModel.cs │ │ └── TabItemModel.cs ├── Wu10Man.csproj ├── app.manifest ├── app.settings.json ├── nlog.config ├── packages.config ├── question.png ├── warning.png └── wu10man.ico ├── stylecop.json └── stylecop.ruleset /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | [Pp]ublish/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | /packages/ 333 | -------------------------------------------------------------------------------- /AdvancedInstaller/.gitignore: -------------------------------------------------------------------------------- 1 | /wu10man-cache/ 2 | -------------------------------------------------------------------------------- /CreatePortable.ps1: -------------------------------------------------------------------------------- 1 | $compress = @{ 2 | Path = "Wu10Man\bin\Release\Wu10Man.exe", 3 | "Wu10Man\bin\Release\app.settings.json", 4 | "Wu10Man\bin\Release\nlog.config", 5 | "Wu10Man\bin\Release\*.dll" 6 | CompressionLevel = "Optimal" 7 | DestinationPath = "Publish\Wu10Man_Portable.zip" 8 | } 9 | Compress-Archive @compress -Force -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/FileAccessBridge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | 6 | // https://stackoverflow.com/questions/1304/how-to-check-for-file-lock#3202085 7 | namespace WereDev.Utils.Win32Wrappers 8 | { 9 | public static class FileAccessBridge 10 | { 11 | [StructLayout(LayoutKind.Sequential)] 12 | struct RM_UNIQUE_PROCESS 13 | { 14 | public int dwProcessId; 15 | public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; 16 | } 17 | 18 | const int RmRebootReasonNone = 0; 19 | const int CCH_RM_MAX_APP_NAME = 255; 20 | const int CCH_RM_MAX_SVC_NAME = 63; 21 | 22 | enum RM_APP_TYPE 23 | { 24 | RmUnknownApp = 0, 25 | RmMainWindow = 1, 26 | RmOtherWindow = 2, 27 | RmService = 3, 28 | RmExplorer = 4, 29 | RmConsole = 5, 30 | RmCritical = 1000 31 | } 32 | 33 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 34 | struct RM_PROCESS_INFO 35 | { 36 | public RM_UNIQUE_PROCESS Process; 37 | 38 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] 39 | public string strAppName; 40 | 41 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] 42 | public string strServiceShortName; 43 | 44 | public RM_APP_TYPE ApplicationType; 45 | public uint AppStatus; 46 | public uint TSSessionId; 47 | [MarshalAs(UnmanagedType.Bool)] 48 | public bool bRestartable; 49 | } 50 | 51 | [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] 52 | static extern int RmRegisterResources(uint pSessionHandle, 53 | UInt32 nFiles, 54 | string[] rgsFilenames, 55 | UInt32 nApplications, 56 | [In] RM_UNIQUE_PROCESS[] rgApplications, 57 | UInt32 nServices, 58 | string[] rgsServiceNames); 59 | 60 | [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] 61 | static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); 62 | 63 | [DllImport("rstrtmgr.dll")] 64 | static extern int RmEndSession(uint pSessionHandle); 65 | 66 | [DllImport("rstrtmgr.dll")] 67 | static extern int RmGetList(uint dwSessionHandle, 68 | out uint pnProcInfoNeeded, 69 | ref uint pnProcInfo, 70 | [In, Out] RM_PROCESS_INFO[] rgAffectedApps, 71 | ref uint lpdwRebootReasons); 72 | 73 | /// 74 | /// Find out what process(es) have a lock on the specified file. 75 | /// 76 | /// Path of the file. 77 | /// Processes locking the file 78 | /// See also: 79 | /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx 80 | /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) 81 | /// 82 | /// 83 | public static List WhoIsLocking(string path) 84 | { 85 | string key = Guid.NewGuid().ToString(); 86 | List processes = new List(); 87 | 88 | int res = RmStartSession(out uint handle, 0, key); 89 | 90 | if (res != 0) 91 | throw new Exception("Could not begin restart session. Unable to determine file locker."); 92 | 93 | try 94 | { 95 | const int ERROR_MORE_DATA = 234; 96 | uint pnProcInfo = 0, 97 | lpdwRebootReasons = RmRebootReasonNone; 98 | 99 | string[] resources = new string[] { path }; // Just checking on one resource. 100 | 101 | res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); 102 | 103 | if (res != 0) 104 | throw new Exception("Could not register resource."); 105 | 106 | //Note: there's a race condition here -- the first call to RmGetList() returns 107 | // the total number of process. However, when we call RmGetList() again to get 108 | // the actual processes this number may have increased. 109 | res = RmGetList(handle, out uint pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); 110 | 111 | if (res == ERROR_MORE_DATA) 112 | { 113 | // Create an array to store the process results 114 | RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; 115 | pnProcInfo = pnProcInfoNeeded; 116 | 117 | // Get the list 118 | res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); 119 | 120 | if (res == 0) 121 | { 122 | processes = new List((int)pnProcInfo); 123 | 124 | // Enumerate all of the results and add them to the 125 | // list to be returned 126 | for (int i = 0; i < pnProcInfo; i++) 127 | { 128 | try 129 | { 130 | processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); 131 | } 132 | // catch the error -- in case the process is no longer running 133 | catch (ArgumentException) { } 134 | } 135 | } 136 | else 137 | throw new Exception("Could not list processes locking resource."); 138 | } 139 | else if (res != 0) 140 | throw new Exception("Could not list processes locking resource. Failed to get size of result."); 141 | } 142 | finally 143 | { 144 | RmEndSession(handle); 145 | } 146 | 147 | return processes; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/Models/ServiceConfigInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace WereDev.Utils.Win32Wrappers.Models 4 | { 5 | [StructLayout(LayoutKind.Sequential)] 6 | public class ServiceConfigInfo 7 | { 8 | [MarshalAs(UnmanagedType.U4)] 9 | public uint ServiceType; 10 | [MarshalAs(UnmanagedType.U4)] 11 | public uint StartType; 12 | [MarshalAs(UnmanagedType.U4)] 13 | public uint ErrorControl; 14 | [MarshalAs(UnmanagedType.LPWStr)] 15 | public string BinaryPathName; 16 | [MarshalAs(UnmanagedType.LPWStr)] 17 | public string LoadOrderGroup; 18 | [MarshalAs(UnmanagedType.U4)] 19 | public uint TagID; 20 | [MarshalAs(UnmanagedType.LPWStr)] 21 | public string Dependencies; 22 | [MarshalAs(UnmanagedType.LPWStr)] 23 | public string ServiceStartName; 24 | [MarshalAs(UnmanagedType.LPWStr)] 25 | public string DisplayName; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("WereDev.Utils.Win32Wrappers")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("WereDev")] 11 | [assembly: AssemblyProduct("WereDev.Utils.Win32Wrappers")] 12 | [assembly: AssemblyCopyright("Copyright © 2018-2022")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("11e7c6da-6d2c-4ffd-9b2b-80646fdf9500")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/WereDev.Utils.Win32Wrappers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500} 8 | Library 9 | Properties 10 | WereDev.Utils.Win32Wrappers 11 | WereDev.Utils.Win32Wrappers 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | SecurityRules.ruleset 27 | 28 | 29 | none 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | true 41 | 42 | 43 | wu10man-snk.pfx 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/WindowsApiBridge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Runtime.InteropServices; 4 | using System.Security.Principal; 5 | 6 | // https://stackoverflow.com/questions/17031552/how-do-you-take-file-ownership-with-powershell/17047190#17047190 7 | namespace WereDev.Utils.Win32Wrappers 8 | { 9 | public static class WindowsApiBridge 10 | { 11 | private const uint SE_PRIVILEGE_ENABLED = 2; 12 | 13 | /// 14 | /// Enables or disables the specified privilege on the primary access token of the current process. 15 | /// 16 | /// Privilege to enable or disable. 17 | /// 18 | /// True to enable the privilege, false to disable it. 19 | /// 20 | /// True if the privilege was enabled prior to the change, false if it was disabled. 21 | public static bool ModifyPrivilege(PrivilegeName privilege, bool enable) 22 | { 23 | if (!LookupPrivilegeValue(null, privilege.ToString(), out Luid luid)) 24 | throw new Win32Exception(); 25 | 26 | using (var identity = WindowsIdentity.GetCurrent(TokenAccessLevels.AdjustPrivileges | TokenAccessLevels.Query)) 27 | { 28 | var newPriv = new TokenPrivileges 29 | { 30 | Privileges = new LuidAndAttributes[] 31 | { 32 | new LuidAndAttributes { 33 | Luid = luid, 34 | Attributes = enable ? SE_PRIVILEGE_ENABLED : 0 35 | } 36 | }, 37 | PrivilegeCount = 1 38 | }; 39 | 40 | var prevPriv = new TokenPrivileges 41 | { 42 | Privileges = new LuidAndAttributes[1], 43 | PrivilegeCount = 1 44 | }; 45 | 46 | if (!AdjustTokenPrivileges(identity.Token, false, ref newPriv, (uint)Marshal.SizeOf(prevPriv), ref prevPriv, out uint returnedBytes)) 47 | throw new Win32Exception(); 48 | 49 | return prevPriv.PrivilegeCount == 0 ? enable /* didn't make a change */ : ((prevPriv.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED) != 0); 50 | } 51 | } 52 | 53 | [DllImport("advapi32.dll", SetLastError = true)] 54 | [return: MarshalAs(UnmanagedType.Bool)] 55 | private extern static bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TokenPrivileges NewState, 56 | UInt32 BufferLengthInBytes, ref TokenPrivileges PreviousState, out UInt32 ReturnLengthInBytes); 57 | 58 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 59 | [return: MarshalAs(UnmanagedType.Bool)] 60 | private extern static bool LookupPrivilegeValue(string lpSystemName, string lpName, out Luid lpLuid); 61 | 62 | private struct TokenPrivileges 63 | { 64 | public UInt32 PrivilegeCount; 65 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1 /*ANYSIZE_ARRAY*/)] 66 | public LuidAndAttributes[] Privileges; 67 | } 68 | 69 | [StructLayout(LayoutKind.Sequential)] 70 | private struct LuidAndAttributes 71 | { 72 | public Luid Luid; 73 | public UInt32 Attributes; 74 | } 75 | 76 | [StructLayout(LayoutKind.Sequential)] 77 | private struct Luid 78 | { 79 | public uint LowPart; 80 | public int HighPart; 81 | } 82 | } 83 | 84 | public enum PrivilegeName 85 | { 86 | SeAssignPrimaryTokenPrivilege, 87 | SeAuditPrivilege, 88 | SeBackupPrivilege, 89 | SeChangeNotifyPrivilege, 90 | SeCreateGlobalPrivilege, 91 | SeCreatePagefilePrivilege, 92 | SeCreatePermanentPrivilege, 93 | SeCreateSymbolicLinkPrivilege, 94 | SeCreateTokenPrivilege, 95 | SeDebugPrivilege, 96 | SeEnableDelegationPrivilege, 97 | SeImpersonatePrivilege, 98 | SeIncreaseBasePriorityPrivilege, 99 | SeIncreaseQuotaPrivilege, 100 | SeIncreaseWorkingSetPrivilege, 101 | SeLoadDriverPrivilege, 102 | SeLockMemoryPrivilege, 103 | SeMachineAccountPrivilege, 104 | SeManageVolumePrivilege, 105 | SeProfileSingleProcessPrivilege, 106 | SeRelabelPrivilege, 107 | SeRemoteShutdownPrivilege, 108 | SeRestorePrivilege, 109 | SeSecurityPrivilege, 110 | SeShutdownPrivilege, 111 | SeSyncAgentPrivilege, 112 | SeSystemEnvironmentPrivilege, 113 | SeSystemProfilePrivilege, 114 | SeSystemtimePrivilege, 115 | SeTakeOwnershipPrivilege, 116 | SeTcbPrivilege, 117 | SeTimeZonePrivilege, 118 | SeTrustedCredManAccessPrivilege, 119 | SeUndockPrivilege, 120 | SeUnsolicitedInputPrivilege, 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /WereDev.Utils.Win32Wrappers/WindowsServiceBridge.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace WereDev.Utils.Win32Wrappers 5 | { 6 | public static class WindowsServiceBridge 7 | { 8 | public const uint SC_MANAGER_ALL_ACCESS = 0x000F003F; 9 | public const uint SC_MANAGER_QUERY_ACESS = 0x10000000; 10 | public const uint SERVICE_NO_CHANGE = 0xffffffff; //this value is found in winsvc.h 11 | public const uint SERVICE_QUERY_CONFIG = 0x00000001; 12 | public const uint SERVICE_CHANGE_CONFIG = 0x00000002; 13 | public const uint SERVICE_QUERY_STATUS = 0x00000004; 14 | public const uint SERVICE_ENUMERATE_DEPENDENTS = 0x00000008; 15 | public const uint SERVICE_START = 0x00000010; 16 | public const uint SERVICE_STOP = 0x00000020; 17 | public const uint SERVICE_PAUSE_CONTINUE = 0x00000040; 18 | public const uint SERVICE_INTERROGATE = 0x00000080; 19 | public const uint SERVICE_USER_DEFINED_CONTROL = 0x00000100; 20 | public const uint STANDARD_RIGHTS_REQUIRED = 0x000F0000; 21 | public const uint SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | 22 | SERVICE_CHANGE_CONFIG | 23 | SERVICE_QUERY_STATUS | 24 | SERVICE_ENUMERATE_DEPENDENTS | 25 | SERVICE_START | 26 | SERVICE_STOP | 27 | SERVICE_PAUSE_CONTINUE | 28 | SERVICE_INTERROGATE | 29 | SERVICE_USER_DEFINED_CONTROL); 30 | 31 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 32 | [return: MarshalAs(UnmanagedType.Bool)] 33 | public static extern bool ChangeServiceConfig(IntPtr hService, UInt32 nServiceType, UInt32 nStartType, UInt32 nErrorControl, String lpBinaryPathName, String lpLoadOrderGroup, IntPtr lpdwTagId, String lpDependencies, String lpServiceStartName, String lpPassword, String lpDisplayName); 34 | 35 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 36 | public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); 37 | 38 | [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] 39 | public static extern IntPtr OpenSCManager( 40 | string machineName, 41 | string databaseName, 42 | uint dwAccess); 43 | 44 | [DllImport("advapi32.dll", SetLastError = true)] 45 | [return: MarshalAs(UnmanagedType.Bool)] 46 | public static extern bool CloseServiceHandle(IntPtr hSCObject); 47 | 48 | [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 49 | public static extern Boolean QueryServiceConfig(IntPtr hService, IntPtr intPtrQueryConfig, UInt32 cbBufSize, out UInt32 pcbBytesNeeded); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/DependencyManager.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Interfaces; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core 4 | { 5 | public static class DependencyManager 6 | { 7 | public static ILogWriter LogWriter { get; set; } 8 | 9 | public static IFileManager FileManager { get; set; } 10 | 11 | public static IRegistryEditor RegistryEditor { get; set; } 12 | 13 | public static IWindowsPackageManager WindowsPackageManager { get; set; } 14 | 15 | public static IHostsFileEditor HostsFileEditor { get; set; } 16 | 17 | public static IWindowsServiceManager WindowsServiceManager { get; set; } 18 | 19 | public static IWindowsTaskManager WindowsTaskManager { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Enums/ServiceStartMode.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Enums 2 | { 3 | public enum ServiceStartMode 4 | { 5 | // Summary: 6 | // Indicates that the service is a device driver started by the system loader. This 7 | // value is valid only for device drivers. 8 | Boot = 0, 9 | 10 | // Summary: 11 | // Indicates that the service is a device driver started by the IOInitSystem function. 12 | // This value is valid only for device drivers. 13 | System = 1, 14 | 15 | // Summary: 16 | // Indicates that the service is to be started (or was started) by the operating 17 | // system, at system start-up. If an automatically started service depends on a 18 | // manually started service, the manually started service is also started automatically 19 | // at system startup. 20 | Automatic = 2, 21 | 22 | // Summary: 23 | // Indicates that the service is started only manually, by a user (using the Service 24 | // Control Manager) or by an application. 25 | Manual = 3, 26 | 27 | // Summary: 28 | // Indicates that the service is disabled, so that it cannot be started by a user 29 | // or application. 30 | Disabled = 4, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Enums/WindowsApiPrivelegeNames.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Enums 2 | { 3 | public enum WindowsApiPrivelegeNames 4 | { 5 | SeAssignPrimaryTokenPrivilege, 6 | SeAuditPrivilege, 7 | SeBackupPrivilege, 8 | SeChangeNotifyPrivilege, 9 | SeCreateGlobalPrivilege, 10 | SeCreatePagefilePrivilege, 11 | SeCreatePermanentPrivilege, 12 | SeCreateSymbolicLinkPrivilege, 13 | SeCreateTokenPrivilege, 14 | SeDebugPrivilege, 15 | SeEnableDelegationPrivilege, 16 | SeImpersonatePrivilege, 17 | SeIncreaseBasePriorityPrivilege, 18 | SeIncreaseQuotaPrivilege, 19 | SeIncreaseWorkingSetPrivilege, 20 | SeLoadDriverPrivilege, 21 | SeLockMemoryPrivilege, 22 | SeMachineAccountPrivilege, 23 | SeManageVolumePrivilege, 24 | SeProfileSingleProcessPrivilege, 25 | SeRelabelPrivilege, 26 | SeRemoteShutdownPrivilege, 27 | SeRestorePrivilege, 28 | SeSecurityPrivilege, 29 | SeShutdownPrivilege, 30 | SeSyncAgentPrivilege, 31 | SeSystemEnvironmentPrivilege, 32 | SeSystemProfilePrivilege, 33 | SeSystemtimePrivilege, 34 | SeTakeOwnershipPrivilege, 35 | SeTcbPrivilege, 36 | SeTimeZonePrivilege, 37 | SeTrustedCredManAccessPrivilege, 38 | SeUndockPrivilege, 39 | SeUnsolicitedInputPrivilege, 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Exceptions/EntityNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Exceptions 4 | { 5 | public class EntityNotFoundException : Exception 6 | { 7 | public EntityNotFoundException(string message, string entityname) 8 | : base(message) 9 | { 10 | EntityName = entityname; 11 | } 12 | 13 | public string EntityName { get; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IFileManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 4 | { 5 | public interface IFileManager 6 | { 7 | void RenameFile(string origPath, string newPath); 8 | 9 | void TakeOwnership(string fileName, string userName); 10 | 11 | void GiveOwnershipToAdministrators(string fileName); 12 | 13 | void GiveOwnershipToTrustedInstaller(string fileName); 14 | 15 | void SetOwnership(string fileName, string userName); 16 | 17 | void GrantFullAccessToFile(string fileName, string userName); 18 | 19 | string GetDirectoryName(string path); 20 | 21 | string GetFileName(string path); 22 | 23 | string Combine(string path1, string path2); 24 | 25 | bool Exists(string path); 26 | 27 | void Delete(string path); 28 | 29 | string[] FindLockingProcesses(string path); 30 | 31 | string[] ReadAllLines(string path); 32 | 33 | void WriteAllLines(string path, IEnumerable lines); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IHostsFileEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 4 | { 5 | public interface IHostsFileEditor 6 | { 7 | void SetHostsEntries(IEnumerable hostUrls); 8 | 9 | void ClearHostsEntries(); 10 | 11 | string[] GetHostsInFile(); 12 | 13 | string[] GetLockingProcessNames(); 14 | 15 | void BlockHostUrl(string hostUrl); 16 | 17 | void UnblockHostUrl(string hostUrl); 18 | 19 | string[] GetManagedHosts(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/ILogWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 4 | { 5 | public interface ILogWriter 6 | { 7 | void LogError(Exception ex); 8 | 9 | void LogError(string message); 10 | 11 | void LogInfo(string message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IRegistryEditor.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 2 | { 3 | public interface IRegistryEditor 4 | { 5 | string ReadLocalMachineRegistryValue(string registryKey, string registryName); 6 | 7 | void WriteLocalMachineRegistryDword(string registryKey, string registryName, string registryValue); 8 | 9 | void WriteLocalMachineRegistryString(string registryKey, string registryName, string registryValue); 10 | 11 | void DeleteLocalMachineRegistryValue(string registryKey, string registryName); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IWindowsPackageManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using WereDev.Utils.Wu10Man.Core.Models; 3 | 4 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 5 | { 6 | public interface IWindowsPackageManager 7 | { 8 | DeclutterConfig GetDeclutterConfig(); 9 | 10 | PackageInfo[] ListInstalledPackages(); 11 | 12 | AppInfoExtended[] MergePackageInfo(IEnumerable apps, IEnumerable packages); 13 | 14 | void RemovePackage(string packageName); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IWindowsServiceManager.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 2 | { 3 | public interface IWindowsServiceManager 4 | { 5 | string[] ListAllServices(); 6 | 7 | bool ServiceExists(string serviceName); 8 | 9 | string GetServiceDisplayName(string serviceName); 10 | 11 | string GetServiceDllPath(string serviceName); 12 | 13 | bool AreAllServicesEnabled(); 14 | 15 | bool AreAllServicesDisabled(); 16 | 17 | bool IsServiceEnabled(string serviceName); 18 | 19 | bool EnableService(string serviceName); 20 | 21 | void DisableService(string serviceName); 22 | 23 | void AddWu10ToFileName(string serviceName); 24 | 25 | void RemoveWu10FromFileName(string serviceName); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/IWindowsTaskManager.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Models; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces 4 | { 5 | public interface IWindowsTaskManager 6 | { 7 | WindowsTask[] GetTasks(); 8 | 9 | WindowsTask GetTask(string path); 10 | 11 | WindowsTask[] DisableTasks(); 12 | 13 | WindowsTask DisableTask(string path); 14 | 15 | WindowsTask[] EnableTasks(); 16 | 17 | WindowsTask EnableTask(string path); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/ICredentialsProvider.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 2 | { 3 | public interface ICredentialsProvider 4 | { 5 | string GetAccountAdministratorUserName(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IFileIoProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.Security.AccessControl; 4 | 5 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 6 | { 7 | public interface IFileIoProvider 8 | { 9 | Process[] FindLockingProcesses(string path); 10 | 11 | bool Exists(string path); 12 | 13 | void Delete(string path); 14 | 15 | void Move(string sourceFile, string destFile); 16 | 17 | FileSecurity GetAccessControl(string path); 18 | 19 | void SetAccessControl(string path, FileSecurity fileSecurity); 20 | 21 | string GetFileName(string path); 22 | 23 | string GetDirectoryName(string path); 24 | 25 | string Combine(string path1, string path2); 26 | 27 | string[] ReadAllLines(string path); 28 | 29 | void WriteAllLines(string path, IEnumerable lines); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IRegistryProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Principal; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 4 | { 5 | public interface IRegistryProvider 6 | { 7 | string ReadLocalMachineRegistryValue(string registryKey, string registryName); 8 | 9 | void WriteLocalMachineRegistryDword(string registryKey, string registryName, string registryValue); 10 | 11 | void WriteLocalMachineRegistryString(string registryKey, string registryName, string registryValue); 12 | 13 | void DeleteLocalMachineRegistryValue(string registryKey, string registryName); 14 | 15 | void TakeLocalMachineOwnership(string registryKey, SecurityIdentifier user); 16 | 17 | void SetLocalMachineWritePermission(string registryKey, SecurityIdentifier user); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IUserProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Principal; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 4 | { 5 | public interface IUserProvider 6 | { 7 | SecurityIdentifier GetCurrentUser(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IWindowsApiProvider.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Enums; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 4 | { 5 | public interface IWindowsApiProvider 6 | { 7 | void ModifyPrivilege(WindowsApiPrivelegeNames privilege, bool enable); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IWindowsPackageProvider.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Models; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 4 | { 5 | public interface IWindowsPackageProvider 6 | { 7 | PackageInfo[] ListInstalledPackages(); 8 | 9 | void RemovePackage(string packageName); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IWindowsServiceProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ServiceProcess; 3 | 4 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 5 | { 6 | public interface IWindowsServiceProvider : IDisposable 7 | { 8 | string DisplayName { get; } 9 | 10 | bool SetStartupType(ServiceStartMode startMode); 11 | 12 | bool ServiceExists(); 13 | 14 | bool TryDisableService(); 15 | 16 | bool TryEnableService(); 17 | 18 | bool IsServiceEnabled(); 19 | 20 | void StopService(); 21 | 22 | void SetAccountAsLocalService(); 23 | 24 | void SetAccountAsLocalSystem(); 25 | 26 | bool IsServiceRunAsLocalSystem(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IWindowsServiceProviderFactory.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 2 | { 3 | public interface IWindowsServiceProviderFactory 4 | { 5 | IWindowsServiceProvider GetWindowsServiceProvider(string service); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Interfaces/Providers/IWindowsTaskProvider.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Models; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Interfaces.Providers 4 | { 5 | public interface IWindowsTaskProvider 6 | { 7 | WindowsTask GetTask(string fullPath); 8 | 9 | void EnableTask(string fullPath); 10 | 11 | void DisableTask(string fullPath); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/AppInfo.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class AppInfo 4 | { 5 | public string AppName { get; set; } 6 | 7 | public string PackageName { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/AppInfoExtended.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class AppInfoExtended : AppInfo 4 | { 5 | public AppInfoExtended(AppInfo appInfo) 6 | { 7 | AppName = appInfo?.AppName; 8 | PackageName = appInfo?.PackageName; 9 | } 10 | 11 | public bool IsInstalled { get; set; } 12 | 13 | public string IconPath { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return AppName; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/DeclutterConfig.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class DeclutterConfig 4 | { 5 | public AppInfo[] Microsoft { get; set; } 6 | 7 | public AppInfo[] ThirdParty { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/PackageInfo.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class PackageInfo 4 | { 5 | public string PackageName { get; set; } 6 | 7 | public string InstallLocation { get; set; } 8 | 9 | public override string ToString() 10 | { 11 | return PackageName; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/SplitHostsFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace WereDev.Utils.Wu10Man.Core.Models 4 | { 5 | internal class SplitHostsFile 6 | { 7 | public SplitHostsFile() 8 | { 9 | Wu10ManLines = new List(); 10 | OtherLines = new List(); 11 | } 12 | 13 | public List Wu10ManLines { get; } 14 | 15 | public List OtherLines { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/WindowsTask.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class WindowsTask 4 | { 5 | public string Name { get; set; } 6 | 7 | public string FullPath { get; set; } 8 | 9 | public bool Enabled { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Models/WindowsTaskConfig.cs: -------------------------------------------------------------------------------- 1 | namespace WereDev.Utils.Wu10Man.Core.Models 2 | { 3 | public class WindowsTaskConfig 4 | { 5 | public string TaskName { get; set; } 6 | 7 | public string TaskPath { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/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("WereDev.Utils.Wu10Man.Core")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("WereDev")] 12 | [assembly: AssemblyProduct("WereDev.Utils.Wu10Man.Core")] 13 | [assembly: AssemblyCopyright("Copyright © 2018-2022")] 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("e10091e5-2789-4515-a7b2-79f316ecd30b")] 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 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/FileManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.AccessControl; 5 | using System.Security.Principal; 6 | using WereDev.Utils.Wu10Man.Core.Exceptions; 7 | using WereDev.Utils.Wu10Man.Core.Interfaces; 8 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 9 | 10 | namespace WereDev.Utils.Wu10Man.Core.Services 11 | { 12 | public class FileManager : IFileManager 13 | { 14 | private readonly string _trustedInstallerUser = @"NT SERVICE\TrustedInstaller"; 15 | private readonly IWindowsApiProvider _windowsApiProvider; 16 | private readonly IFileIoProvider _fileIoProvider; 17 | private readonly ICredentialsProvider _credentialsProvider; 18 | 19 | public FileManager(IFileIoProvider fileIoProvider, IWindowsApiProvider windowsApiProvider, ICredentialsProvider credentialsProvider) 20 | { 21 | _fileIoProvider = fileIoProvider ?? throw new ArgumentNullException(nameof(fileIoProvider)); 22 | _windowsApiProvider = windowsApiProvider ?? throw new ArgumentNullException(nameof(windowsApiProvider)); 23 | _credentialsProvider = credentialsProvider ?? throw new ArgumentNullException(nameof(credentialsProvider)); 24 | } 25 | 26 | public void RenameFile(string origPath, string newPath) 27 | { 28 | if (_fileIoProvider.Exists(origPath)) 29 | { 30 | _fileIoProvider.Move(origPath, newPath); 31 | } 32 | } 33 | 34 | public void TakeOwnership(string fileName, string userName) 35 | { 36 | SetOwnership(fileName, userName); 37 | } 38 | 39 | public void GiveOwnershipToAdministrators(string fileName) 40 | { 41 | var username = _credentialsProvider.GetAccountAdministratorUserName(); 42 | SetOwnership(fileName, username); 43 | GrantFullAccessToFile(fileName, username); 44 | } 45 | 46 | public void GiveOwnershipToTrustedInstaller(string fileName) 47 | { 48 | SetOwnership(fileName, _trustedInstallerUser); 49 | } 50 | 51 | public void SetOwnership(string fileName, string userName) 52 | { 53 | if (string.IsNullOrWhiteSpace(userName)) 54 | throw new ArgumentNullException(nameof(userName)); 55 | 56 | var fileSecurity = GetFileSecurity(fileName); 57 | var account = new NTAccount(userName); 58 | fileSecurity.SetOwner(account); 59 | _fileIoProvider.SetAccessControl(fileName, fileSecurity); 60 | } 61 | 62 | public void GrantFullAccessToFile(string fileName, string userName) 63 | { 64 | if (string.IsNullOrWhiteSpace(userName)) 65 | throw new ArgumentNullException(nameof(userName)); 66 | 67 | var fileSecurity = GetFileSecurity(fileName); 68 | var account = new NTAccount(userName); 69 | fileSecurity.SetAccessRule(new FileSystemAccessRule(account, FileSystemRights.FullControl, AccessControlType.Allow)); 70 | _fileIoProvider.SetAccessControl(fileName, fileSecurity); 71 | } 72 | 73 | public string[] ReadAllLines(string path) 74 | { 75 | return _fileIoProvider.ReadAllLines(path); 76 | } 77 | 78 | public void WriteAllLines(string path, IEnumerable lines) 79 | { 80 | _fileIoProvider.WriteAllLines(path, lines); 81 | } 82 | 83 | public string[] FindLockingProcesses(string path) 84 | { 85 | var processes = _fileIoProvider.FindLockingProcesses(path); 86 | return processes.Select(x => x.MainModule?.FileVersionInfo?.ProductName ?? x.ProcessName).ToArray(); 87 | } 88 | 89 | public string GetFileName(string path) 90 | { 91 | return _fileIoProvider.GetFileName(path); 92 | } 93 | 94 | public string Combine(string path1, string path2) 95 | { 96 | return _fileIoProvider.Combine(path1, path2); 97 | } 98 | 99 | public bool Exists(string path) 100 | { 101 | return _fileIoProvider.Exists(path); 102 | } 103 | 104 | public void Delete(string path) 105 | { 106 | _fileIoProvider.Delete(path); 107 | } 108 | 109 | public string GetDirectoryName(string path) 110 | { 111 | return _fileIoProvider.GetDirectoryName(path); 112 | } 113 | 114 | private FileSecurity GetFileSecurity(string fileName) 115 | { 116 | if (string.IsNullOrWhiteSpace(fileName)) 117 | throw new ArgumentNullException(nameof(fileName)); 118 | if (!_fileIoProvider.Exists(fileName)) 119 | throw new EntityNotFoundException("Could not find file to set ownership.", fileName); 120 | 121 | // Allow this process to circumvent ACL restrictions 122 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeRestorePrivilege, true); 123 | 124 | // Sometimes this is required and other times it works without it. Not sure when. 125 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeTakeOwnershipPrivilege, true); 126 | 127 | var accessControl = _fileIoProvider.GetAccessControl(fileName); 128 | 129 | return accessControl; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/HostsFileEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | using WereDev.Utils.Wu10Man.Core.Models; 7 | 8 | namespace WereDev.Utils.Wu10Man.Core.Services 9 | { 10 | public class HostsFileEditor : IHostsFileEditor 11 | { 12 | private const string HostsFilePath = @"drivers\etc\hosts"; 13 | private const string Wu10ManStart = "# Start of entries added by Wu10Man"; 14 | private const string OldWu10ManStart = "# Start of entried added by Wu10Man"; // was misspelled but left here for backwards compatibility 15 | private const string Wu10ManEnd = "# End of entries added by Wu10Man"; 16 | private const string OldWu10ManEnd = "# End of entried added by Wu10Man"; // was misspelled but left here for backwards compatibility 17 | private const string NullEndpoint = "0.0.0.0\t"; 18 | 19 | private readonly IFileIoProvider _fileIoProvider; 20 | private readonly string[] _windowsUpdateUrls; 21 | 22 | public HostsFileEditor(IFileIoProvider fileIoProvider, string[] windowsUpateUrls) 23 | { 24 | _fileIoProvider = fileIoProvider ?? throw new ArgumentNullException(nameof(fileIoProvider)); 25 | _windowsUpdateUrls = windowsUpateUrls ?? new string[0]; 26 | } 27 | 28 | private string HostsFile => _fileIoProvider.Combine(Environment.SystemDirectory, HostsFilePath); 29 | 30 | public void SetHostsEntries(IEnumerable hostUrls) 31 | { 32 | var lines = ReadHostsFile(); 33 | var split = SplitLines(lines); 34 | split.Wu10ManLines.Clear(); 35 | var hosts = CreateLinesFromHosts(hostUrls); 36 | split.Wu10ManLines.AddRange(hosts); 37 | WriteHostsFile(split); 38 | } 39 | 40 | public void ClearHostsEntries() 41 | { 42 | var lines = ReadHostsFile(); 43 | var split = SplitLines(lines); 44 | split.Wu10ManLines.Clear(); 45 | WriteHostsFile(split); 46 | } 47 | 48 | public string[] GetHostsInFile() 49 | { 50 | var lines = ReadHostsFile(); 51 | var split = SplitLines(lines); 52 | var hosts = GetHostsFromLines(split.Wu10ManLines); 53 | if (hosts == null) 54 | return Array.Empty(); 55 | else 56 | return hosts.Select(x => StandardizeHostUrl(x)).Distinct().ToArray(); 57 | } 58 | 59 | public string[] GetManagedHosts() 60 | { 61 | var uniques = _windowsUpdateUrls.Select(x => StandardizeHostUrl(x)).Distinct(); 62 | return uniques.ToArray(); 63 | } 64 | 65 | public string[] GetLockingProcessNames() 66 | { 67 | var processes = _fileIoProvider.FindLockingProcesses(HostsFile); 68 | return processes.Select(x => x.MainModule?.FileVersionInfo?.ProductName ?? x.ProcessName).ToArray(); 69 | } 70 | 71 | public void BlockHostUrl(string hostUrl) 72 | { 73 | if (string.IsNullOrWhiteSpace(hostUrl)) 74 | throw new ArgumentNullException(nameof(hostUrl)); 75 | hostUrl = StandardizeHostUrl(hostUrl); 76 | if (!GetManagedHosts().Contains(hostUrl)) 77 | throw new InvalidOperationException("Host URL not monitored by Wu10Man: " + hostUrl); 78 | var currentHosts = GetHostsInFile(); 79 | if (!currentHosts.Contains(hostUrl)) 80 | { 81 | var hostsList = currentHosts.ToList(); 82 | hostsList.Add(hostUrl); 83 | SetHostsEntries(hostsList); 84 | } 85 | } 86 | 87 | public void UnblockHostUrl(string hostUrl) 88 | { 89 | if (string.IsNullOrWhiteSpace(hostUrl)) 90 | throw new ArgumentNullException(nameof(hostUrl)); 91 | hostUrl = StandardizeHostUrl(hostUrl); 92 | if (!GetManagedHosts().Contains(hostUrl)) 93 | throw new InvalidOperationException("Host URL not monitored by Wu10Man: " + hostUrl); 94 | var currentHosts = GetHostsInFile(); 95 | if (currentHosts.Contains(hostUrl)) 96 | { 97 | var hostsList = currentHosts.ToList(); 98 | hostsList.Remove(hostUrl); 99 | SetHostsEntries(hostsList); 100 | } 101 | } 102 | 103 | private string StandardizeHostUrl(string hostUrl) 104 | { 105 | if (string.IsNullOrWhiteSpace(hostUrl)) 106 | hostUrl = string.Empty; 107 | 108 | return hostUrl.Trim().ToLower(); 109 | } 110 | 111 | private string[] GetHostsFromLines(IEnumerable lines) 112 | { 113 | var hosts = lines.Select(x => GetHostFromLine(x)) 114 | .Where(x => !string.IsNullOrEmpty(x)) 115 | .ToArray(); 116 | return hosts; 117 | } 118 | 119 | private string GetHostFromLine(string line) 120 | { 121 | line = line.Trim(); 122 | if (string.IsNullOrEmpty(line)) 123 | return line; 124 | var split = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); 125 | return split[1]; 126 | } 127 | 128 | private string[] CreateLinesFromHosts(IEnumerable hosts) 129 | { 130 | if (hosts?.Any() == true) 131 | { 132 | var lines = hosts.Select(x => NullEndpoint + x); 133 | return lines.ToArray(); 134 | } 135 | 136 | return new string[0]; 137 | } 138 | 139 | private string[] ReadHostsFile() 140 | { 141 | var lines = _fileIoProvider.ReadAllLines(HostsFile); 142 | return lines; 143 | } 144 | 145 | private SplitHostsFile SplitLines(IEnumerable lines) 146 | { 147 | var splitLines = new SplitHostsFile(); 148 | bool wu10Line = false; 149 | 150 | foreach (var line in lines) 151 | { 152 | switch (line) 153 | { 154 | case Wu10ManStart: 155 | case OldWu10ManStart: 156 | wu10Line = true; 157 | break; 158 | case Wu10ManEnd: 159 | case OldWu10ManEnd: 160 | wu10Line = false; 161 | break; 162 | default: 163 | if (wu10Line) 164 | splitLines.Wu10ManLines.Add(line); 165 | else 166 | splitLines.OtherLines.Add(line); 167 | break; 168 | } 169 | } 170 | 171 | return splitLines; 172 | } 173 | 174 | private void WriteHostsFile(SplitHostsFile splitHostsFile) 175 | { 176 | List lines = new List(splitHostsFile.OtherLines); 177 | 178 | if (splitHostsFile.Wu10ManLines.Any()) 179 | { 180 | lines.Add(Wu10ManStart); 181 | lines.AddRange(splitHostsFile.Wu10ManLines); 182 | lines.Add(Wu10ManEnd); 183 | } 184 | 185 | _fileIoProvider.WriteAllLines(HostsFile, lines); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/RegistryEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security; 3 | using WereDev.Utils.Wu10Man.Core.Interfaces; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 5 | 6 | namespace WereDev.Utils.Wu10Man.Core.Services 7 | { 8 | public class RegistryEditor : IRegistryEditor 9 | { 10 | private readonly IWindowsApiProvider _windowsApiProvider; 11 | private readonly IRegistryProvider _registryProvider; 12 | private readonly IUserProvider _userProvider; 13 | 14 | public RegistryEditor(IWindowsApiProvider windowsApiProvider, IRegistryProvider registryProvider, IUserProvider userProvider) 15 | { 16 | _windowsApiProvider = windowsApiProvider ?? throw new ArgumentNullException(nameof(windowsApiProvider)); 17 | _registryProvider = registryProvider ?? throw new ArgumentNullException(nameof(registryProvider)); 18 | _userProvider = userProvider ?? throw new ArgumentNullException(nameof(userProvider)); 19 | } 20 | 21 | public string ReadLocalMachineRegistryValue(string registryKey, string registryName) 22 | { 23 | if (string.IsNullOrWhiteSpace(registryKey)) 24 | throw new ArgumentNullException(nameof(registryKey)); 25 | if (string.IsNullOrWhiteSpace(registryName)) 26 | throw new ArgumentNullException(nameof(registryName)); 27 | 28 | return _registryProvider.ReadLocalMachineRegistryValue(registryKey, registryName); 29 | } 30 | 31 | public void WriteLocalMachineRegistryString(string registryKey, string registryName, string registryValue) 32 | { 33 | try 34 | { 35 | _registryProvider.WriteLocalMachineRegistryString(registryKey, registryName, registryValue); 36 | } 37 | catch (Exception ex) 38 | { 39 | if (ex is UnauthorizedAccessException || ex is SecurityException) 40 | { 41 | TakeOwnership(registryKey); 42 | SetWritePermission(registryKey); 43 | _registryProvider.WriteLocalMachineRegistryString(registryKey, registryName, registryValue); 44 | } 45 | } 46 | } 47 | 48 | public void WriteLocalMachineRegistryDword(string registryKey, string registryName, string registryValue) 49 | { 50 | try 51 | { 52 | _registryProvider.WriteLocalMachineRegistryDword(registryKey, registryName, registryValue); 53 | } 54 | catch (Exception ex) 55 | { 56 | if (ex is UnauthorizedAccessException || ex is SecurityException) 57 | { 58 | TakeOwnership(registryKey); 59 | SetWritePermission(registryKey); 60 | _registryProvider.WriteLocalMachineRegistryDword(registryKey, registryName, registryValue); 61 | } 62 | } 63 | } 64 | 65 | public void DeleteLocalMachineRegistryValue(string registryKey, string registryName) 66 | { 67 | try 68 | { 69 | _registryProvider.DeleteLocalMachineRegistryValue(registryKey, registryName); 70 | } 71 | catch (Exception ex) 72 | { 73 | if (ex is UnauthorizedAccessException || ex is SecurityException) 74 | { 75 | TakeOwnership(registryKey); 76 | SetWritePermission(registryKey); 77 | _registryProvider.DeleteLocalMachineRegistryValue(registryKey, registryName); 78 | } 79 | } 80 | } 81 | 82 | private void TakeOwnership(string registryKey) 83 | { 84 | try 85 | { 86 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeRestorePrivilege, true); 87 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeBackupPrivilege, true); 88 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeTakeOwnershipPrivilege, true); 89 | _registryProvider.TakeLocalMachineOwnership(registryKey, _userProvider.GetCurrentUser()); 90 | } 91 | finally 92 | { 93 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeRestorePrivilege, false); 94 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeBackupPrivilege, false); 95 | _windowsApiProvider.ModifyPrivilege(Enums.WindowsApiPrivelegeNames.SeTakeOwnershipPrivilege, false); 96 | } 97 | } 98 | 99 | private void SetWritePermission(string registryKey) 100 | { 101 | _registryProvider.SetLocalMachineWritePermission(registryKey, _userProvider.GetCurrentUser()); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/WindowsPackageManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | using WereDev.Utils.Wu10Man.Core.Models; 7 | 8 | namespace WereDev.Utils.Wu10Man.Core.Services 9 | { 10 | public class WindowsPackageManager : IWindowsPackageManager 11 | { 12 | private readonly IWindowsPackageProvider _packageProvider; 13 | private readonly DeclutterConfig _declutterConfig; 14 | 15 | public WindowsPackageManager(IWindowsPackageProvider packageProvider, DeclutterConfig declutterConfig) 16 | { 17 | _packageProvider = packageProvider ?? throw new ArgumentNullException(nameof(packageProvider)); 18 | _declutterConfig = declutterConfig ?? new DeclutterConfig(); 19 | } 20 | 21 | public DeclutterConfig GetDeclutterConfig() 22 | { 23 | return _declutterConfig; 24 | } 25 | 26 | public PackageInfo[] ListInstalledPackages() 27 | { 28 | return _packageProvider.ListInstalledPackages(); 29 | } 30 | 31 | public AppInfoExtended[] MergePackageInfo(IEnumerable apps, IEnumerable packages) 32 | { 33 | List appInfos = new List(); 34 | foreach (var app in apps) 35 | { 36 | var appInfo = new AppInfoExtended(app); 37 | var package = packages.FirstOrDefault(x => x.PackageName == app.PackageName); 38 | if (package != null) 39 | { 40 | appInfo.IsInstalled = true; 41 | } 42 | 43 | appInfos.Add(appInfo); 44 | } 45 | 46 | return appInfos.ToArray(); 47 | } 48 | 49 | public void RemovePackage(string packageName) 50 | { 51 | _packageProvider.RemovePackage(packageName); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/WindowsServiceManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using WereDev.Utils.Wu10Man.Core.Enums; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | 7 | namespace WereDev.Utils.Wu10Man.Core.Services 8 | { 9 | public class WindowsServiceManager : IWindowsServiceManager 10 | { 11 | private readonly string _wu10FilePrefix = "Wu10Man_"; 12 | private readonly string _serviceRegistryPath = @"SYSTEM\CurrentControlSet\Services\"; 13 | private readonly IWindowsServiceProviderFactory _providerFactory; 14 | private readonly IRegistryEditor _registryEditor; // TODO: Not a fan of this because of possible circular reference 15 | private readonly IFileManager _fileManager; 16 | private readonly string[] _windowsServices; 17 | 18 | public WindowsServiceManager(IWindowsServiceProviderFactory providerFactory, IRegistryEditor registryEditor, IFileManager fileManager, string[] windowsServices) 19 | { 20 | _providerFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory)); 21 | _registryEditor = registryEditor ?? throw new ArgumentNullException(nameof(registryEditor)); 22 | _fileManager = fileManager ?? throw new ArgumentNullException(nameof(fileManager)); 23 | _windowsServices = windowsServices ?? new string[0]; 24 | } 25 | 26 | public string[] ListAllServices() 27 | { 28 | return _windowsServices; 29 | } 30 | 31 | public bool ServiceExists(string serviceName) 32 | { 33 | if (string.IsNullOrWhiteSpace(serviceName)) 34 | throw new ArgumentNullException(nameof(serviceName)); 35 | using (var service = _providerFactory.GetWindowsServiceProvider(serviceName)) 36 | { 37 | return service.ServiceExists(); 38 | } 39 | } 40 | 41 | public string GetServiceDisplayName(string serviceName) 42 | { 43 | if (string.IsNullOrWhiteSpace(serviceName)) 44 | throw new ArgumentNullException(nameof(serviceName)); 45 | using (var service = _providerFactory.GetWindowsServiceProvider(serviceName)) 46 | { 47 | return service.DisplayName; 48 | } 49 | } 50 | 51 | public string GetServiceDllPath(string serviceName) 52 | { 53 | if (string.IsNullOrWhiteSpace(serviceName)) 54 | throw new ArgumentNullException(nameof(serviceName)); 55 | 56 | return _registryEditor.ReadLocalMachineRegistryValue(_serviceRegistryPath + serviceName + @"\Parameters", "ServiceDll"); 57 | } 58 | 59 | public bool AreAllServicesEnabled() 60 | { 61 | return ListAllServices().All(x => IsServiceEnabled(x)); 62 | } 63 | 64 | public bool AreAllServicesDisabled() 65 | { 66 | return ListAllServices().All(x => !IsServiceEnabled(x)); 67 | } 68 | 69 | public bool IsServiceEnabled(string serviceName) 70 | { 71 | if (string.IsNullOrWhiteSpace(serviceName)) 72 | throw new ArgumentNullException(nameof(serviceName)); 73 | var serviceDllPath = GetServiceDllPath(serviceName); 74 | 75 | using (var service = _providerFactory.GetWindowsServiceProvider(serviceName)) 76 | { 77 | return service.IsServiceEnabled() 78 | && (string.IsNullOrEmpty(serviceDllPath) || _fileManager.Exists(serviceDllPath)); 79 | } 80 | } 81 | 82 | public bool EnableService(string serviceName) 83 | { 84 | if (string.IsNullOrWhiteSpace(serviceName)) 85 | throw new ArgumentNullException(nameof(serviceName)); 86 | RemoveWu10FromFileName(serviceName); 87 | var enabledRealtime = false; 88 | using (var service = _providerFactory.GetWindowsServiceProvider(serviceName)) 89 | { 90 | if (!service.IsServiceRunAsLocalSystem()) 91 | service.SetAccountAsLocalSystem(); 92 | enabledRealtime = service.TryEnableService(); 93 | if (!enabledRealtime) 94 | { 95 | SetStartModeViaRegistry(serviceName, ServiceStartMode.Manual); 96 | } 97 | } 98 | 99 | return enabledRealtime; 100 | } 101 | 102 | public void DisableService(string serviceName) 103 | { 104 | if (string.IsNullOrWhiteSpace(serviceName)) 105 | throw new ArgumentNullException(nameof(serviceName)); 106 | using (var service = _providerFactory.GetWindowsServiceProvider(serviceName)) 107 | { 108 | if (!service.TryDisableService()) 109 | { 110 | SetStartModeViaRegistry(serviceName, ServiceStartMode.Disabled); 111 | } 112 | } 113 | 114 | AddWu10ToFileName(serviceName); 115 | } 116 | 117 | public void AddWu10ToFileName(string serviceName) 118 | { 119 | var dllPath = GetServiceDllPath(serviceName); 120 | if (string.IsNullOrEmpty(dllPath)) 121 | return; 122 | 123 | _fileManager.GiveOwnershipToAdministrators(dllPath); 124 | var wu10Path = GetPathWithWu10Prefix(dllPath); 125 | _fileManager.RenameFile(dllPath, wu10Path); 126 | } 127 | 128 | public void RemoveWu10FromFileName(string serviceName) 129 | { 130 | var dllPath = GetServiceDllPath(serviceName); 131 | if (string.IsNullOrEmpty(dllPath)) 132 | return; 133 | 134 | var wu10Path = GetPathWithWu10Prefix(dllPath); 135 | 136 | // If the file has returned, then we need to assume that some other process has recreated 137 | // it. It's safer to assume the new file is correct and delete the "old" file. 138 | if (_fileManager.Exists(dllPath)) 139 | { 140 | _fileManager.Delete(wu10Path); 141 | } 142 | else 143 | { 144 | _fileManager.GiveOwnershipToAdministrators(wu10Path); 145 | _fileManager.RenameFile(wu10Path, dllPath); 146 | _fileManager.GiveOwnershipToTrustedInstaller(dllPath); 147 | } 148 | } 149 | 150 | private string GetPathWithWu10Prefix(string path) 151 | { 152 | var folder = _fileManager.GetDirectoryName(path); 153 | var fileName = _fileManager.GetFileName(path); 154 | if (fileName.StartsWith(_wu10FilePrefix, StringComparison.CurrentCultureIgnoreCase)) 155 | return path; 156 | 157 | fileName = _wu10FilePrefix + fileName; 158 | var newPath = _fileManager.Combine(folder, fileName); 159 | return newPath; 160 | } 161 | 162 | private void SetStartModeViaRegistry(string serviceName, ServiceStartMode startMode) 163 | { 164 | _registryEditor.WriteLocalMachineRegistryDword( 165 | _serviceRegistryPath + serviceName, 166 | "Start", 167 | ((int)startMode).ToString()); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/Services/WindowsTaskManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | using WereDev.Utils.Wu10Man.Core.Models; 7 | 8 | namespace WereDev.Utils.Wu10Man.Core.Services 9 | { 10 | public class WindowsTaskManager : IWindowsTaskManager 11 | { 12 | private readonly IWindowsTaskProvider _taskProvider; 13 | private readonly WindowsTaskConfig[] _windowsTaskConfigs; 14 | 15 | public WindowsTaskManager(IWindowsTaskProvider taskProvider, WindowsTaskConfig[] windowsTaskConfigs) 16 | { 17 | _taskProvider = taskProvider ?? throw new ArgumentNullException(nameof(taskProvider)); 18 | _windowsTaskConfigs = windowsTaskConfigs ?? new WindowsTaskConfig[0]; 19 | var distinct = _windowsTaskConfigs.GroupBy(x => x.TaskPath) 20 | .Select(x => x.First()) 21 | .ToArray(); 22 | _windowsTaskConfigs = distinct; 23 | } 24 | 25 | public WindowsTask[] DisableTasks() 26 | { 27 | foreach (var config in _windowsTaskConfigs) 28 | { 29 | _taskProvider.DisableTask(config.TaskPath); 30 | } 31 | 32 | return GetTasks(); 33 | } 34 | 35 | public WindowsTask DisableTask(string path) 36 | { 37 | _taskProvider.DisableTask(path); 38 | return _taskProvider.GetTask(path); 39 | } 40 | 41 | public WindowsTask[] EnableTasks() 42 | { 43 | foreach (var config in _windowsTaskConfigs) 44 | { 45 | _taskProvider.EnableTask(config.TaskPath); 46 | } 47 | 48 | return GetTasks(); 49 | } 50 | 51 | public WindowsTask EnableTask(string path) 52 | { 53 | _taskProvider.EnableTask(path); 54 | return _taskProvider.GetTask(path); 55 | } 56 | 57 | public WindowsTask[] GetTasks() 58 | { 59 | var tasks = new List(); 60 | foreach (var config in _windowsTaskConfigs) 61 | { 62 | var task = _taskProvider.GetTask(config.TaskPath); 63 | if (task == null) 64 | continue; 65 | var pathSplit = task.FullPath.Split('\\'); 66 | task.Name = pathSplit[pathSplit.Length - 2] + " - " + task.Name; 67 | tasks.Add(task); 68 | } 69 | 70 | return tasks.ToArray(); 71 | } 72 | 73 | public WindowsTask GetTask(string path) 74 | { 75 | var task = _taskProvider.GetTask(path); 76 | var taskFromCollection = _windowsTaskConfigs.FirstOrDefault(x => x.TaskPath.Equals(path, StringComparison.OrdinalIgnoreCase)); 77 | task.Name = taskFromCollection?.TaskName ?? task.Name; 78 | return task; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/WereDev.Utils.Wu10Man.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {E10091E5-2789-4515-A7B2-79F316ECD30B} 10 | Library 11 | Properties 12 | WereDev.Utils.Wu10Man.Core 13 | WereDev.Utils.Wu10Man.Core 14 | v4.7.2 15 | 512 16 | true 17 | 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | ..\stylecop.ruleset 28 | 29 | 30 | none 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | ..\stylecop.ruleset 37 | 38 | 39 | true 40 | 41 | 42 | wu10man-snk.pfx 43 | 44 | 45 | 46 | 47 | 48 | ..\packages\System.Diagnostics.EventLog.5.0.1\lib\net461\System.Diagnostics.EventLog.dll 49 | 50 | 51 | ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll 52 | 53 | 54 | ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll 55 | 56 | 57 | 58 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | stylecop.json 100 | 101 | 102 | stylecop.ruleset 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Core/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/CredentialsProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Principal; 2 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 3 | 4 | namespace WereDev.Utils.Wu10Man.Providers 5 | { 6 | public class CredentialsProvider : ICredentialsProvider 7 | { 8 | public string GetAccountAdministratorUserName() 9 | { 10 | return GetUserName(WellKnownSidType.AccountAdministratorSid); 11 | } 12 | 13 | public string GetUserName(WellKnownSidType sidType) 14 | { 15 | var sid = new SecurityIdentifier(sidType, WindowsIdentity.GetCurrent().User.AccountDomainSid); 16 | var account = sid.Translate(typeof(NTAccount)); 17 | return account.Value; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/FileIoProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Security.AccessControl; 6 | using WereDev.Utils.Win32Wrappers; 7 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 8 | 9 | namespace WereDev.Utils.Wu10Man.Providers 10 | { 11 | public class FileIoProvider : IFileIoProvider 12 | { 13 | public bool Exists(string path) 14 | { 15 | return File.Exists(path); 16 | } 17 | 18 | public void Move(string sourceFile, string destFile) 19 | { 20 | File.Move(sourceFile, destFile); 21 | } 22 | 23 | public void SetAccessControl(string path, FileSecurity fileSecurity) 24 | { 25 | File.SetAccessControl(path, fileSecurity); 26 | } 27 | 28 | public Process[] FindLockingProcesses(string path) 29 | { 30 | if (string.IsNullOrWhiteSpace(path)) 31 | throw new ArgumentNullException(nameof(path)); 32 | 33 | return FileAccessBridge.WhoIsLocking(path)?.ToArray(); 34 | } 35 | 36 | public void Delete(string path) 37 | { 38 | File.Delete(path); 39 | } 40 | 41 | public FileSecurity GetAccessControl(string path) 42 | { 43 | return File.GetAccessControl(path); 44 | } 45 | 46 | public string GetFileName(string path) 47 | { 48 | return Path.GetFileName(path); 49 | } 50 | 51 | public string GetDirectoryName(string path) 52 | { 53 | return Path.GetDirectoryName(path); 54 | } 55 | 56 | public string Combine(string path1, string path2) 57 | { 58 | return Path.Combine(path1, path2); 59 | } 60 | 61 | public string[] ReadAllLines(string path) 62 | { 63 | return File.ReadAllLines(path); 64 | } 65 | 66 | public void WriteAllLines(string path, IEnumerable lines) 67 | { 68 | File.WriteAllLines(path, lines); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/PowerShellProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Management.Automation; 3 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 4 | using WereDev.Utils.Wu10Man.Core.Models; 5 | 6 | namespace WereDev.Utils.Wu10Man.Providers 7 | { 8 | public class PowerShellProvider : IWindowsPackageProvider 9 | { 10 | private const string CommandGetPackages = "Get-AppxPackage"; 11 | private const string CommandRemovePackage = "Get-AppxPackage *{0}* | Remove-AppxPackage"; 12 | private const string CommandRemoveProvisionedPackage = "Get-AppxProvisionedPackage -Online | where Displayname -EQ *{0}*| Remove-AppxProvisionedPackage -Online"; 13 | 14 | public PackageInfo[] ListInstalledPackages() 15 | { 16 | var packages = new List(); 17 | using (var ps = PowerShell.Create()) 18 | { 19 | ps.AddCommand(CommandGetPackages); 20 | var results = ps.Invoke(); 21 | 22 | foreach (var result in results) 23 | { 24 | dynamic appx = result.BaseObject; 25 | var package = new PackageInfo() 26 | { 27 | PackageName = appx.Name, 28 | }; 29 | packages.Add(package); 30 | } 31 | } 32 | 33 | return packages.ToArray(); 34 | } 35 | 36 | public void RemovePackage(string packageName) 37 | { 38 | using (var ps = PowerShell.Create()) 39 | { 40 | ps.AddScript(string.Format(CommandRemovePackage, packageName)); 41 | ps.AddScript(string.Format(CommandRemoveProvisionedPackage, packageName)); 42 | var results = ps.Invoke(); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/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("WereDev.Utils.Wu10Man.Providers")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("WereDev")] 12 | [assembly: AssemblyProduct("WereDev.Utils.Wu10Man.Providers")] 13 | [assembly: AssemblyCopyright("Copyright © 2018-2022")] 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("2c880065-bd13-4abb-b3fc-11ecd25625de")] 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 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/RegistryProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using System; 3 | using System.Security.AccessControl; 4 | using System.Security.Principal; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | 7 | namespace WereDev.Utils.Wu10Man.Providers 8 | { 9 | public class RegistryProvider : IRegistryProvider 10 | { 11 | public string ReadLocalMachineRegistryValue(string registryKey, string registryName) 12 | { 13 | if (string.IsNullOrWhiteSpace(registryKey)) 14 | throw new ArgumentNullException(nameof(registryKey)); 15 | if (string.IsNullOrWhiteSpace(registryName)) 16 | throw new ArgumentNullException(nameof(registryName)); 17 | using (var regKey = Registry.LocalMachine.OpenSubKey(registryKey)) 18 | { 19 | var regValue = regKey?.GetValue(registryName); 20 | return regValue?.ToString(); 21 | } 22 | } 23 | 24 | public void WriteLocalMachineRegistryString(string registryKey, string registryName, string registryValue) 25 | { 26 | WriteRegistryValue(Registry.LocalMachine, registryKey, registryName, registryValue, RegistryValueKind.String); 27 | } 28 | 29 | public void WriteLocalMachineRegistryDword(string registryKey, string registryName, string registryValue) 30 | { 31 | WriteRegistryValue(Registry.LocalMachine, registryKey, registryName, registryValue, RegistryValueKind.DWord); 32 | } 33 | 34 | public void DeleteLocalMachineRegistryValue(string registryKey, string registryName) 35 | { 36 | DeleteRegistryValue(Registry.LocalMachine, registryKey, registryName); 37 | } 38 | 39 | public void TakeLocalMachineOwnership(string registryKey, SecurityIdentifier user) 40 | { 41 | TakeOwnership(Registry.LocalMachine, registryKey, user); 42 | } 43 | 44 | public void SetLocalMachineWritePermission(string registryKey, SecurityIdentifier user) 45 | { 46 | SetWritePermission(Registry.LocalMachine, registryKey, user); 47 | } 48 | 49 | private void WriteRegistryValue(RegistryKey registryRoot, string registryKey, string registryName, string registryValue, RegistryValueKind registryValueKind) 50 | { 51 | if (registryRoot == null) 52 | throw new ArgumentNullException(nameof(registryRoot)); 53 | if (string.IsNullOrWhiteSpace(registryKey)) 54 | throw new ArgumentNullException(nameof(registryKey)); 55 | if (string.IsNullOrWhiteSpace(registryName)) 56 | throw new ArgumentNullException(nameof(registryName)); 57 | 58 | using (var regKey = OpenOrCreateRegistryKey(registryRoot, registryKey, true)) 59 | { 60 | regKey.SetValue(registryName, registryValue, registryValueKind); 61 | regKey.Flush(); 62 | } 63 | } 64 | 65 | private RegistryKey OpenOrCreateRegistryKey(RegistryKey registryRoot, string registryKey, bool writable) 66 | { 67 | var regKey = registryRoot.OpenSubKey(registryKey, writable); 68 | if (regKey == null) 69 | regKey = registryRoot.CreateSubKey(registryKey, writable); 70 | regKey.Flush(); 71 | return regKey; 72 | } 73 | 74 | private void DeleteRegistryValue(RegistryKey registryRoot, string registryKey, string registryName) 75 | { 76 | if (registryRoot == null) 77 | throw new ArgumentNullException(nameof(registryRoot)); 78 | if (string.IsNullOrWhiteSpace(registryKey)) 79 | throw new ArgumentNullException(nameof(registryKey)); 80 | if (string.IsNullOrWhiteSpace(registryName)) 81 | throw new ArgumentNullException(nameof(registryName)); 82 | 83 | using (var regKey = registryRoot.OpenSubKey(registryKey, false)) 84 | { 85 | var value = regKey.GetValue(registryName); 86 | if (value == null) 87 | return; 88 | } 89 | 90 | using (var regKey = registryRoot.OpenSubKey(registryKey, true)) 91 | { 92 | regKey.DeleteValue(registryName); 93 | } 94 | } 95 | 96 | private void TakeOwnership(RegistryKey registryRoot, string registryKey, SecurityIdentifier user) 97 | { 98 | using (var regKey = registryRoot.OpenSubKey(registryKey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership)) 99 | { 100 | var regSec = regKey.GetAccessControl(); 101 | regSec.SetOwner(user); 102 | regKey.SetAccessControl(regSec); 103 | } 104 | } 105 | 106 | private void SetWritePermission(RegistryKey registryRoot, string registryKey, SecurityIdentifier user) 107 | { 108 | using (var regKey = registryRoot.OpenSubKey(registryKey, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ChangePermissions)) 109 | { 110 | var regSec = regKey.GetAccessControl(); 111 | 112 | RegistryAccessRule regRule = new RegistryAccessRule( 113 | user, 114 | RegistryRights.FullControl, 115 | InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, 116 | PropagationFlags.None, 117 | AccessControlType.Allow); 118 | 119 | regSec.AddAccessRule(regRule); 120 | regKey.SetAccessControl(regSec); 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/UserProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Principal; 2 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 3 | 4 | namespace WereDev.Utils.Wu10Man.Providers 5 | { 6 | public class UserProvider : IUserProvider 7 | { 8 | public SecurityIdentifier GetCurrentUser() 9 | { 10 | return WindowsIdentity.GetCurrent().User; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/WindowsApiProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using WereDev.Utils.Win32Wrappers; 3 | using WereDev.Utils.Wu10Man.Core.Enums; 4 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 5 | 6 | namespace WereDev.Utils.Wu10Man.Providers 7 | { 8 | public class WindowsApiProvider : IWindowsApiProvider 9 | { 10 | public void ModifyPrivilege(WindowsApiPrivelegeNames privilege, bool enable) 11 | { 12 | var privlegeName = (PrivilegeName)Enum.Parse(typeof(PrivilegeName), privilege.ToString()); 13 | WindowsApiBridge.ModifyPrivilege(privlegeName, enable); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/WindowsServiceProviderFactory.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 2 | 3 | namespace WereDev.Utils.Wu10Man.Providers 4 | { 5 | public class WindowsServiceProviderFactory : IWindowsServiceProviderFactory 6 | { 7 | public IWindowsServiceProvider GetWindowsServiceProvider(string service) 8 | { 9 | return new WindowsServiceProvider(service); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/WindowsTaskProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.TaskScheduler; 2 | using System; 3 | using System.Security.Principal; 4 | using System.Threading; 5 | using WereDev.Utils.Wu10Man.Core.Interfaces.Providers; 6 | using WereDev.Utils.Wu10Man.Core.Models; 7 | 8 | namespace WereDev.Utils.Wu10Man.Providers 9 | { 10 | public class WindowsTaskProvider : IWindowsTaskProvider 11 | { 12 | private readonly string _wu10TaskPath = "Wu10Man Admin Task"; 13 | 14 | public WindowsTaskProvider() 15 | { 16 | } 17 | 18 | public void DisableTask(string fullPath) 19 | { 20 | RunAdminTask("Disable-ScheduledTask", fullPath); 21 | } 22 | 23 | public void EnableTask(string fullPath) 24 | { 25 | RunAdminTask("Enable-ScheduledTask", fullPath); 26 | } 27 | 28 | public WindowsTask GetTask(string fullPath) 29 | { 30 | using (var task = TaskService.Instance.GetTask(fullPath)) 31 | { 32 | if (task == null) 33 | return null; 34 | 35 | return new WindowsTask 36 | { 37 | Enabled = task.Enabled, 38 | FullPath = fullPath, 39 | Name = task.Name, 40 | }; 41 | } 42 | } 43 | 44 | private void RunAdminTask(string toExecute, string fullPath) 45 | { 46 | CleanupAdminTask(); 47 | 48 | using (var task = CreateHelperTask(toExecute, fullPath)) 49 | { 50 | task.Run(); 51 | } 52 | 53 | WaitForAdminTaskCompletion(); 54 | 55 | CleanupAdminTask(); 56 | } 57 | 58 | private Task CreateHelperTask(string toExecute, string fullPath) 59 | { 60 | var sid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, WindowsIdentity.GetCurrent().User.AccountDomainSid); 61 | var account = sid.Translate(typeof(NTAccount)); 62 | var username = account.Value; 63 | 64 | return TaskService.Instance.AddTask( 65 | _wu10TaskPath, 66 | new TimeTrigger() { StartBoundary = DateTime.Now, Enabled = false }, 67 | new ExecAction( 68 | @"powershell", 69 | $" -command \"& {{ {toExecute} -TaskName '{fullPath}' }}\"", 70 | Environment.CurrentDirectory), 71 | userId: username, 72 | logonType: TaskLogonType.ServiceAccount, 73 | description: "Task used by Wu10Man to enable other tasks"); 74 | } 75 | 76 | private void CleanupAdminTask() 77 | { 78 | using (var oldTask = TaskService.Instance.GetTask(_wu10TaskPath)) 79 | { 80 | if (oldTask != null) 81 | { 82 | oldTask.Stop(); 83 | TaskService.Instance.RootFolder.DeleteTask(_wu10TaskPath); 84 | } 85 | } 86 | } 87 | 88 | private void WaitForAdminTaskCompletion() 89 | { 90 | while (true) 91 | { 92 | using (var task = TaskService.Instance.GetTask(_wu10TaskPath)) 93 | { 94 | if (task.State != TaskState.Running) 95 | break; 96 | else 97 | Thread.Sleep(100); 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /WereDev.Utils.Wu10Man.Providers/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Wu10Man.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wu10Man", "Wu10Man\Wu10Man.csproj", "{5162DE0E-A9CE-480D-A550-E4F8833E5D26}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WereDev.Utils.Win32Wrappers", "WereDev.Utils.Win32Wrappers\WereDev.Utils.Win32Wrappers.csproj", "{11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WereDev.Utils.Wu10Man.Core", "WereDev.Utils.Wu10Man.Core\WereDev.Utils.Wu10Man.Core.csproj", "{E10091E5-2789-4515-A7B2-79F316ECD30B}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WereDev.Utils.Wu10Man.Providers", "WereDev.Utils.Wu10Man.Providers\WereDev.Utils.Wu10Man.Providers.csproj", "{2C880065-BD13-4ABB-B3FC-11ECD25625DE}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {5162DE0E-A9CE-480D-A550-E4F8833E5D26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {5162DE0E-A9CE-480D-A550-E4F8833E5D26}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {5162DE0E-A9CE-480D-A550-E4F8833E5D26}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {5162DE0E-A9CE-480D-A550-E4F8833E5D26}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {11E7C6DA-6D2C-4FFD-9B2B-80646FDF9500}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {E10091E5-2789-4515-A7B2-79F316ECD30B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {E10091E5-2789-4515-A7B2-79F316ECD30B}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {E10091E5-2789-4515-A7B2-79F316ECD30B}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {E10091E5-2789-4515-A7B2-79F316ECD30B}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {2C880065-BD13-4ABB-B3FC-11ECD25625DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {2C880065-BD13-4ABB-B3FC-11ECD25625DE}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {2C880065-BD13-4ABB-B3FC-11ECD25625DE}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {2C880065-BD13-4ABB-B3FC-11ECD25625DE}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {5FF65910-90B3-413F-B7D3-A1F3D40FC5C1} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /Wu10Man/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | -------------------------------------------------------------------------------- /Wu10Man/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.IO; 4 | using System.Windows; 5 | using WereDev.Utils.Wu10Man.Core; 6 | using WereDev.Utils.Wu10Man.Core.Interfaces; 7 | using WereDev.Utils.Wu10Man.Core.Services; 8 | using WereDev.Utils.Wu10Man.Providers; 9 | using WereDev.Utils.Wu10Man.Services; 10 | using WereDev.Utils.Wu10Man.UserWindows; 11 | 12 | namespace WereDev.Utils.Wu10Man 13 | { 14 | /// 15 | /// Interaction logic for App.xaml. 16 | /// 17 | public partial class App : Application 18 | { 19 | private readonly ILogWriter _logWriter = new Wu10Logger(); 20 | 21 | public App() 22 | : base() 23 | { 24 | _logWriter.LogInfo("Application starting"); 25 | try 26 | { 27 | RegisterDependencies(); 28 | WriteStartupLogs(); 29 | Dispatcher.UnhandledException += OnDispatcherUnhandledException; 30 | MainWindow = new MainWindow(); 31 | MainWindow.Show(); 32 | 33 | _logWriter.LogInfo("Application started"); 34 | } 35 | catch (Exception ex) 36 | { 37 | _logWriter.LogError(ex); 38 | MessageBox.Show("An error occured attempting to initialize the application. Check the log file for more details.", "Error!", MessageBoxButton.OK, MessageBoxImage.Error); 39 | Shutdown(); 40 | } 41 | } 42 | 43 | protected override void OnExit(ExitEventArgs e) 44 | { 45 | _logWriter.LogInfo("Application ended"); 46 | base.OnExit(e); 47 | } 48 | 49 | private void RegisterDependencies() 50 | { 51 | DependencyManager.LogWriter = _logWriter; 52 | var appSettings = GetAppSettings(); 53 | 54 | // Providers 55 | var credentialsProvider = new CredentialsProvider(); 56 | var fileIoProvider = new FileIoProvider(); 57 | var registryProvider = new RegistryProvider(); 58 | var userProvider = new UserProvider(); 59 | var windowsApiProvider = new WindowsApiProvider(); 60 | var windowsServiceProviderFactory = new WindowsServiceProviderFactory(); 61 | var powerShellProvider = new PowerShellProvider(); 62 | var windowsTaskProvider = new WindowsTaskProvider(); 63 | 64 | // Services 65 | var fileManager = new FileManager(fileIoProvider, windowsApiProvider, credentialsProvider); 66 | DependencyManager.FileManager = fileManager; 67 | DependencyManager.HostsFileEditor = new HostsFileEditor(fileIoProvider, appSettings.WindowsUpdateUrls); 68 | var registryEditor = new RegistryEditor(windowsApiProvider, registryProvider, userProvider); 69 | DependencyManager.RegistryEditor = registryEditor; 70 | DependencyManager.WindowsServiceManager = new WindowsServiceManager(windowsServiceProviderFactory, registryEditor, fileManager, appSettings.WindowsServices); 71 | DependencyManager.WindowsPackageManager = new WindowsPackageManager(powerShellProvider, appSettings.Declutter); 72 | DependencyManager.WindowsTaskManager = new WindowsTaskManager(windowsTaskProvider, appSettings.WindowsTasks); 73 | } 74 | 75 | private AppSettings GetAppSettings() 76 | { 77 | var appSettingsFile = File.ReadAllText("./app.settings.json"); 78 | var appSettings = JsonConvert.DeserializeObject(appSettingsFile); 79 | return appSettings; 80 | } 81 | 82 | private void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) 83 | { 84 | _logWriter.LogError(e.Exception); 85 | string errorMessage = string.Format("{0}\r\n\r\nCheck the logs for more details.", e.Exception.Message); 86 | MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); 87 | e.Handled = true; 88 | } 89 | 90 | private void WriteStartupLogs() 91 | { 92 | var appVersion = GetType().Assembly.GetName().Version; 93 | _logWriter.LogInfo($"Application version: v{appVersion}"); 94 | 95 | var registryEditor = DependencyManager.RegistryEditor; 96 | _logWriter.LogInfo(EnvironmentVersionHelper.GetWindowsVersion(registryEditor)); 97 | _logWriter.LogInfo($".Net Framework: {EnvironmentVersionHelper.GetDotNetFrameworkBuild(registryEditor)}"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Wu10Man/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using WereDev.Utils.Wu10Man.Core.Models; 2 | 3 | namespace WereDev.Utils.Wu10Man 4 | { 5 | internal class AppSettings 6 | { 7 | public string[] WindowsUpdateUrls { get; set; } 8 | 9 | public string[] WindowsServices { get; set; } 10 | 11 | public DeclutterConfig Declutter { get; set; } 12 | 13 | public WindowsTaskConfig[] WindowsTasks { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Wu10Man/Converters/MathConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Windows.Data; 6 | 7 | namespace WereDev.Utils.Wu10Man.Converters 8 | { 9 | // Does a math equation on the bound value. 10 | // Use @VALUE in your mathEquation as a substitute for bound value 11 | // Operator order is parenthesis first, then Left-To-Right (no operator precedence) 12 | // https://rachel53461.wordpress.com/2011/08/20/the-math-converter/ 13 | public class MathConverter : IValueConverter 14 | { 15 | private static readonly char[] _allOperators = new[] { '+', '-', '*', '/', '%', '(', ')' }; 16 | 17 | private static readonly List _grouping = new List { "(", ")" }; 18 | private static readonly List _operators = new List { "+", "-", "*", "/", "%" }; 19 | 20 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 21 | { 22 | // Parse value into equation and remove spaces 23 | var mathEquation = parameter as string; 24 | mathEquation = mathEquation.Replace(" ", string.Empty); 25 | mathEquation = mathEquation.Replace("@VALUE", value?.ToString() ?? string.Empty); 26 | 27 | // Validate values and get list of numbers in equation 28 | var numbers = new List(); 29 | foreach (string s in mathEquation.Split(_allOperators)) 30 | { 31 | if (!string.IsNullOrEmpty(s)) 32 | { 33 | if (double.TryParse(s, out var tmp)) 34 | { 35 | numbers.Add(tmp); 36 | } 37 | else 38 | { 39 | // Handle Error - Some non-numeric, operator, or grouping character found in string 40 | throw new InvalidCastException(); 41 | } 42 | } 43 | } 44 | 45 | // Begin parsing method 46 | EvaluateMathString(ref mathEquation, ref numbers, 0); 47 | 48 | // After parsing the numbers list should only have one value - the total 49 | return numbers[0]; 50 | } 51 | 52 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | 57 | // Evaluates a mathematical string and keeps track of the results in a List of numbers 58 | private void EvaluateMathString(ref string mathEquation, ref List numbers, int index) 59 | { 60 | // Loop through each mathemtaical token in the equation 61 | string token = GetNextToken(mathEquation); 62 | 63 | while (!string.IsNullOrEmpty(token)) 64 | { 65 | // Remove token from mathEquation 66 | mathEquation = mathEquation.Remove(0, token.Length); 67 | 68 | // If token is a grouping character, it affects program flow 69 | if (_grouping.Contains(token)) 70 | { 71 | switch (token) 72 | { 73 | case "(": 74 | EvaluateMathString(ref mathEquation, ref numbers, index); 75 | break; 76 | 77 | case ")": 78 | return; 79 | } 80 | } 81 | 82 | // If token is an operator, do requested operation 83 | if (_operators.Contains(token)) 84 | { 85 | // If next token after operator is a parenthesis, call method recursively 86 | string nextToken = GetNextToken(mathEquation); 87 | if (nextToken == "(") 88 | { 89 | EvaluateMathString(ref mathEquation, ref numbers, index + 1); 90 | } 91 | 92 | // Verify that enough numbers exist in the List to complete the operation 93 | // and that the next token is either the number expected, or it was a ( meaning 94 | // that this was called recursively and that the number changed 95 | if (numbers.Count > (index + 1) && 96 | (double.Parse(nextToken) == numbers[index + 1] || nextToken == "(")) 97 | { 98 | switch (token) 99 | { 100 | case "+": 101 | numbers[index] = numbers[index] + numbers[index + 1]; 102 | break; 103 | case "-": 104 | numbers[index] = numbers[index] - numbers[index + 1]; 105 | break; 106 | case "*": 107 | numbers[index] = numbers[index] * numbers[index + 1]; 108 | break; 109 | case "/": 110 | numbers[index] = numbers[index] / numbers[index + 1]; 111 | break; 112 | case "%": 113 | numbers[index] = numbers[index] % numbers[index + 1]; 114 | break; 115 | } 116 | 117 | numbers.RemoveAt(index + 1); 118 | } 119 | else 120 | { 121 | // Handle Error - Next token is not the expected number 122 | throw new FormatException("Next token is not the expected number"); 123 | } 124 | } 125 | 126 | token = GetNextToken(mathEquation); 127 | } 128 | } 129 | 130 | // Gets the next mathematical token in the equation 131 | private string GetNextToken(string mathEquation) 132 | { 133 | // If we're at the end of the equation, return string.empty 134 | if (string.IsNullOrEmpty(mathEquation)) 135 | { 136 | return string.Empty; 137 | } 138 | 139 | // Get next operator or numeric value in equation and return it 140 | string tmp = string.Empty; 141 | foreach (char c in mathEquation) 142 | { 143 | if (_allOperators.Contains(c)) 144 | { 145 | return string.IsNullOrEmpty(tmp) ? c.ToString() : tmp; 146 | } 147 | else 148 | { 149 | tmp += c; 150 | } 151 | } 152 | 153 | return tmp; 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Wu10Man/CustomDictionary.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | declutter 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Wu10Man/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.InteropServices; 4 | using System.Windows; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("Wu10Man")] 10 | [assembly: AssemblyDescription("Windows 10 Update Manager")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("WereDev")] 13 | [assembly: AssemblyProduct("Wu10Man")] 14 | [assembly: AssemblyCopyright("Copyright WereDev © 2018-2022")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // In order to begin building localizable applications, set 24 | // CultureYouAreCodingWith in your .csproj file 25 | // inside a . For example, if you are using US english 26 | // in your source files, set the to en-US. Then uncomment 27 | // the NeutralResourceLanguage attribute below. Update the "en-US" in 28 | // the line below to match the UICulture setting in the project file. 29 | 30 | // [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 31 | 32 | [assembly: ThemeInfo( 33 | ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located 34 | // (used if a resource is not found in the page, 35 | // or application resource dictionaries) 36 | ResourceDictionaryLocation.SourceAssembly) // where the generic resource dictionary is located 37 | // (used if a resource is not found in the page, 38 | // app, or any theme specific resource dictionaries) 39 | ] 40 | 41 | // Version information for an assembly consists of the following four values: 42 | // 43 | // Major Version 44 | // Minor Version 45 | // Build Number 46 | // Revision 47 | // 48 | // You can specify all the values or you can default the Build and Revision Numbers 49 | // by using the '*' as shown below: 50 | // [assembly: AssemblyVersion("1.0.*")] 51 | [assembly: AssemblyVersion("4.4.0.0")] 52 | [assembly: AssemblyFileVersion("4.4.0.0")] 53 | [assembly: NeutralResourcesLanguage("en-US")] 54 | -------------------------------------------------------------------------------- /Wu10Man/Services/EnvironmentVersionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using WereDev.Utils.Wu10Man.Core.Interfaces; 3 | 4 | namespace WereDev.Utils.Wu10Man.Services 5 | { 6 | public static class EnvironmentVersionHelper 7 | { 8 | private const string WindowsVersionRegistryKey = @"SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion"; 9 | private const string DotNetVersionRegistryKey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"; 10 | 11 | public static string GetDotNetFrameworkBuild(IRegistryEditor registryEditor) 12 | { 13 | if (registryEditor == null) 14 | throw new ArgumentNullException(nameof(registryEditor)); 15 | 16 | var release = registryEditor.ReadLocalMachineRegistryValue(DotNetVersionRegistryKey, "Release"); 17 | int.TryParse(release, out var releaseInt); 18 | 19 | if (releaseInt >= 528040) 20 | return $"{release} / 4.8 or later"; 21 | else if (releaseInt >= 461808) 22 | return $"{release} / 4.7.2"; 23 | else if (releaseInt >= 461308) 24 | return $"{release} / 4.7.1"; 25 | else if (releaseInt >= 460798) 26 | return $"{release} / 4.7"; 27 | else if (releaseInt >= 394802) 28 | return $"{release} / 4.6.2"; 29 | else if (releaseInt >= 394254) 30 | return $"{release} / 4.6.1"; 31 | else if (releaseInt >= 393295) 32 | return $"{release} / 4.6"; 33 | else if (releaseInt >= 393273) 34 | return $"{release} / 4.6 RC"; 35 | else if (releaseInt >= 379893) 36 | return $"{release} / 4.5.2"; 37 | else if (releaseInt >= 378675) 38 | return $"{release} / 4.5.1"; 39 | else if (releaseInt >= 378389) 40 | return $"{release} / 4.5"; 41 | else 42 | return $"{release} / No 4.5 or later version detected"; 43 | } 44 | 45 | public static string GetWindowsVersion(IRegistryEditor registryEditor) 46 | { 47 | if (registryEditor == null) 48 | throw new ArgumentNullException(nameof(registryEditor)); 49 | 50 | var windowsProduct = registryEditor.ReadLocalMachineRegistryValue(WindowsVersionRegistryKey, "ProductName"); 51 | var windowsRelease = registryEditor.ReadLocalMachineRegistryValue(WindowsVersionRegistryKey, "ReleaseId"); 52 | var windowsBuild = registryEditor.ReadLocalMachineRegistryValue(WindowsVersionRegistryKey, "CurrentBuild"); 53 | var windowsBuildRevision = registryEditor.ReadLocalMachineRegistryValue(WindowsVersionRegistryKey, "BaseBuildRevisionNumber"); 54 | return $"{windowsProduct} Version {windowsRelease} Build {windowsBuild}.{windowsBuildRevision}"; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Wu10Man/Services/Wu10Logger.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using NLog.Targets; 3 | using System; 4 | using System.Diagnostics.CodeAnalysis; 5 | using System.IO; 6 | using WereDev.Utils.Wu10Man.Core.Interfaces; 7 | 8 | namespace WereDev.Utils.Wu10Man.Services 9 | { 10 | internal class Wu10Logger : ILogWriter 11 | { 12 | private readonly Logger _logger = LogManager.GetCurrentClassLogger(); 13 | 14 | [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "nlog", Justification="nlog.config is the expected file name.")] 15 | public string LogFolder 16 | { 17 | get 18 | { 19 | var targets = LogManager.Configuration.AllTargets; 20 | foreach (var target in targets) 21 | { 22 | if (target is FileTarget fileTarget) 23 | { 24 | var logEventInfo = new LogEventInfo { TimeStamp = DateTime.Now }; 25 | var fileName = fileTarget.FileName.Render(logEventInfo); 26 | var folder = Path.GetDirectoryName(fileName); 27 | return folder; 28 | } 29 | } 30 | 31 | throw new InvalidOperationException("No file logging has been configured in nlog.config"); 32 | } 33 | } 34 | 35 | public void LogError(Exception ex) 36 | { 37 | var exception = ex; 38 | while (exception != null) 39 | { 40 | LogError($"{exception.GetType()}: {exception.Message}\r\n{exception.StackTrace}"); 41 | exception = exception.InnerException; 42 | } 43 | } 44 | 45 | public void LogError(string message) 46 | { 47 | _logger.Error(message); 48 | } 49 | 50 | public void LogInfo(string message) 51 | { 52 | _logger.Info(message ?? string.Empty); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Wu10Man/UserControls/DeclutterControl.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 |