-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathDiagnostic.cs
260 lines (235 loc) · 10.2 KB
/
Diagnostic.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.AccessControl;
using System.Security.Policy;
using System.Security.Principal;
using System.ServiceProcess;
namespace TaskSchedulerConfig
{
class Diagnostics : List<Diagnostics.Diagnostic>
{
ServicesDetail v;
public Diagnostics(string server)
{
v = new ServicesDetail(server);
Add(new Diagnostic
{
Name = "V1 Local Access: User has insufficient permissions to schedule tasks",
Description = "To schedule a V1 task, the current user must be a member of the Administrators, Backup Operators, or Server Operators group on the local computer.",
Condition = o => v.IsLocal,
Troubleshooter = o => !(v.UserIsAdmin || v.UserIsBackupOperator || v.UserIsServerOperator),
Resolution = new Resolution
{
Name = "Add user to Administrators group",
Description = "Adding the user to the Administrators group will give it the right to schedule a V1 task.",
RequiresConsent = true,
RequiresElevation = true,
Resolver = AddUserRole
}
});
Add(new Diagnostic
{
Name = "V1 Remote Access: Firewall is not enabled",
Description = "Firewall must be enabled on local system.",
Condition = o => v.IsLocal,
Troubleshooter = o => !v.Firewall.Enabled,
Resolution = new Resolution
{
Name = "Enable the firewall",
Description = "Enabling the firewall allows for the Task Scheduler to secure its interactions.",
RequiresElevation = true,
Resolver = o => v.Firewall.Enabled = true
}
});
Add(new Diagnostic
{
Name = "V1 Remote Access: \"File and Printer Sharing\" rule on the firewall is not enabled",
Description = "The \"File and Printer Sharing\" rule must be enabled in order for the Task Scheduler V1 to share its information with other computers.",
Troubleshooter = o => !v.Firewall.Rules[Firewall.Rule.FileAndPrinterSharing],
Resolution = new Resolution
{
Name = "Enable the \"File and Printer Sharing\" rule on the firewall",
Description = "Enabling the \"File and Printer Sharing\" rule on the firewall allows the Task Scheduler V1 to share its information with other computers.",
RequiresElevation = true,
Resolver = o => v.Firewall.Rules[Firewall.Rule.FileAndPrinterSharing] = true
}
});
Add(new Diagnostic
{
Name = "V1 Local Access: Invalid permissions on the \"%windir%\\Tasks\" directory",
Description = "Permissions on the \"%windir%\\Tasks\" directory do not allow V1 tasks to be created or edited by the current user",
Condition = o => v.IsLocal,
Troubleshooter = CheckTasksDirPerms,
Resolution = new Resolution
{
Name = "Give current user access to \"%windir%\\Tasks\" directory",
Description = "Giving the current user access to the \"%windir%\\Tasks\" directory will, in effect, give the user the right to create or edit V1 tasks.",
RequiresConsent = true,
RequiresElevation = true,
Resolver = UpdateTasksDirPerms
}
});
if (System.Environment.OSVersion.Version.Major < 6)
return;
Add(new Diagnostic
{
Name = "V2 Local Access: User has insufficient permissions to schedule tasks",
Description = "To schedule a V2 task, the current user must have \"Log on as a batch job\" and \"Log on as a service\" privileges.",
Condition = o => v.IsLocal,
//Troubleshooter = o => !v.UserRights[LocalSecurityAccountPrivileges.LogonAsBatchJob],
RequiresElevation = true,
Troubleshooter = o => !v.UserAccessRights[LocalSecurity.LsaSecurityAccessRights.BatchLogon],
Resolution = new Resolution
{
Name = "Grant user \"Log on as a batch job\" right",
Description = "Adding the \"Log on as a batch job\" right to the user will give it the right to schedule a V2 task on this and other computers.",
RequiresConsent = true,
RequiresElevation = true,
Resolver = o => v.UserAccessRights[LocalSecurity.LsaSecurityAccessRights.BatchLogon] = true,
}
});
Add(new Diagnostic
{
Name = "V2 Remote Access: \"Remote Task Management\" rule on the firewall is not enabled",
Description = "The \"Remote Task Management\" rule must be enabled in order for the Task Scheduler V2 to share its information with other computers.",
Troubleshooter = o => !v.Firewall.Rules[Firewall.Rule.RemoteTaskManagement],
Resolution = new Resolution
{
Name = "Enable the \"Remote Task Management\" rule on the firewall",
Description = "Enabling the \"Remote Task Management\" rule on the firewall allows the Task Scheduler V2 to share its information with other computers.",
RequiresElevation = true,
Resolver = o => v.Firewall.Rules[Firewall.Rule.RemoteTaskManagement] = true
}
});
Add(new Diagnostic
{
Name = "V2 Remote Event Access: \"Remote Event Log Management\" rule on the firewall is not enabled",
Description = "The \"Remote Event Log Management\" rule must be enabled in order for the Task Scheduler V2 to share its events with other computers.",
Troubleshooter = o => !v.Firewall.Rules[Firewall.Rule.RemoteEventLogManagment],
Resolution = new Resolution
{
Name = "Enable the \"Remote Event Log Management\" rule on the firewall",
Description = "Enabling the \"Remote Event Log Management\" rule on the firewall allows the Task Scheduler V2 to share its events with other computers.",
RequiresElevation = true,
Resolver = o => v.Firewall.Rules[Firewall.Rule.RemoteEventLogManagment] = true
}
});
Add(new Diagnostic
{
Name = "V2 Remote Access: \"Remote Registry\" service is not running",
Description = "The \"Remote Registry\" service must be running in order for the Task Scheduler V1 to connect to this computer.",
Troubleshooter = o => !v.RemoteRegistryServiceRunning,
Resolution = new Resolution
{
Name = "Automatically start the \"Remote Registry\" service",
Description = "Starting the \"Remote Registry\" service and setting that service to start automatically will ensure that other V1 computers can connect to this computer.",
RequiresElevation = true,
Resolver = StartRemoteRegistryService
}
});
}
public event EventHandler<ShowMessageEventArgs> ShowMessage;
public IEnumerable<Diagnostic> Issues
{
get
{
foreach (var item in this)
{
if (item.HasIssue.HasValue && item.HasIssue.Value)
yield return item;
}
}
}
public IEnumerable<Diagnostic> NonIsseus
{
get
{
foreach (var item in this)
{
if (item.Condition(null) && item.HasIssue.HasValue && !item.HasIssue.Value)
yield return item;
}
}
}
public string Server => v.Server;
public IEnumerable<Diagnostic> UnRun
{
get
{
foreach (var item in this)
{
if (item.Condition(null) && !item.HasIssue.HasValue)
yield return item;
}
}
}
private void ShowThisMessage(string s) { ShowMessage?.Invoke(this, new ShowMessageEventArgs(s)); }
private void AddUserRole(object role)
{
throw new InvalidOperationException("You must add the current user manually to the Administrators, Backup Operators, or Server Operators group.");
}
private bool CheckTasksDirPerms(object obj)
{
ShowThisMessage("Checking permissions on \\Windows\\Tasks folder...");
var dir = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Tasks"));
return !DirectoryHasPermission(dir, FileSystemRights.FullControl);
}
private static bool DirectoryHasPermission(DirectoryInfo DirectoryPath, FileSystemRights AccessRight)
{
if (DirectoryPath != null)
try { return (DirectoryPath.GetEffectiveRights(WindowsIdentity.GetCurrent()) & AccessRight) == AccessRight; } catch { }
return false;
}
private void StartRemoteRegistryService(object obj)
{
if (v.RemoteRegistryService.Status != System.ServiceProcess.ServiceControllerStatus.Stopped && v.RemoteRegistryService.CanStop)
{
ShowThisMessage("Stopping \"Remote Registry\" service...");
v.RemoteRegistryService.Stop();
v.RemoteRegistryService.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
}
if (v.RemoteRegistryService.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
{
ShowThisMessage("Setting \"Remote Registry\" service to start automatically...");
v.RemoteRegistryService.SetStartType(System.ServiceProcess.ServiceStartMode.Automatic);
ShowThisMessage("Starting \"Remote Registry\" service...");
v.RemoteRegistryService.Start();
v.RemoteRegistryService.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
}
}
private void UpdateTasksDirPerms(object obj)
{
ShowThisMessage("Adding user rights to \\Windows\\Tasks folder...");
string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Tasks");
var di = new DirectoryInfo(dir);
var sec = di.GetAccessControl(AccessControlSections.Access);
sec.AddAccessRule(new FileSystemAccessRule(v.sid, FileSystemRights.Modify, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
di.SetAccessControl(sec);
}
public class Diagnostic
{
public bool? HasIssue { get; set; }
public bool? Resolved { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Predicate<object> Condition { get; set; } = o => true;
public bool RequiresElevation { get; set; } = false;
public Predicate<object> Troubleshooter { get; set; }
public Resolution Resolution { get; set; }
}
public class Resolution
{
public string Name { get; set; }
public string Description { get; set; }
public bool RequiresConsent { get; set; } = false;
public bool RequiresElevation { get; set; } = false;
public Action<object> Resolver { get; set; }
}
public class ShowMessageEventArgs : EventArgs
{
public ShowMessageEventArgs(string msg) { Message = msg; }
public string Message { get; }
}
}
}