Skip to content

Commit 655bd99

Browse files
committed
Merge branch 'master' of https://github.com/dahall/TaskScheduler
2 parents 31e7853 + 396f337 commit 655bd99

File tree

3 files changed

+89
-10
lines changed

3 files changed

+89
-10
lines changed

TaskEditor/TaskSchedulerWizard.fr.resx

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@
142142
<value>Ouvrir les propriétés de cette tâche quand j’aurai cliqué sur Terminer</value>
143143
</data>
144144
<data name="openFileDialog1.Filter" xml:space="preserve">
145-
<value>Tous les fichiers (*.*)</value>
145+
<value>Tous les fichiers (*.*)|*.*</value>
146146
</data>
147147
<data name="repeatCheckBox.Text" xml:space="preserve">
148148
<value>Répéter la tâche toutes les :</value>
@@ -204,4 +204,4 @@
204204
<data name="monthlyTriggerPage.Text" xml:space="preserve">
205205
<value>Programme d’installation un déclencheur mensuel</value>
206206
</data>
207-
</root>
207+
</root>

TaskService/TaskEventWatcher.cs

+15-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel.Design;
44
using System.Diagnostics.Eventing.Reader;
55
using System.IO;
6+
using System.Security;
67
using JetBrains.Annotations;
78

89
namespace Microsoft.Win32.TaskScheduler
@@ -252,6 +253,19 @@ public TaskEventWatcher(string machineName, string taskPath, string domain = nul
252253
InitTask(taskPath);
253254
}
254255

256+
/// <summary>
257+
/// Initializes a new instance of the <see cref="TaskEventWatcher" /> class on a remote machine.
258+
/// </summary>
259+
/// <param name="machineName">Name of the remote machine.</param>
260+
/// <param name="taskPath">The task path.</param>
261+
/// <param name="domain">The domain of the user account.</param>
262+
/// <param name="user">The user name with permissions on the remote machine.</param>
263+
/// <param name="securePassword">The password for the user as a secure string.</param>
264+
public TaskEventWatcher(string machineName, string taskPath, string domain = null, string user = null, SecureString securePassword = null) : this(new TaskService(machineName, user, domain, securePassword))
265+
{
266+
InitTask(taskPath);
267+
}
268+
255269
/// <summary>
256270
/// Initializes a new instance of the <see cref="TaskEventWatcher" /> class on a remote machine.
257271
/// </summary>
@@ -610,7 +624,7 @@ private void SetupWatcher()
610624
}
611625
else
612626
{
613-
var log = new TaskEventLog(taskPath, Filter.EventIds, Filter.EventLevels, DateTime.UtcNow, TargetServer, UserAccountDomain, UserName, UserPassword);
627+
var log = new TaskEventLog(taskPath, Filter.EventIds, Filter.EventLevels, DateTime.UtcNow, TargetServer, UserAccountDomain, UserName, TaskService.UserPasswordPlainText);
614628
log.Query.ReverseDirection = false;
615629
watcher = new EventLogWatcher(log.Query);
616630
watcher.EventRecordWritten += Watcher_EventRecordWritten;

TaskService/TaskService.cs

+72-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.ComponentModel;
55
using System.IO;
66
using System.Runtime.InteropServices;
7+
using System.Security;
78

89
namespace Microsoft.Win32.TaskScheduler
910
{
@@ -96,6 +97,7 @@ public sealed partial class TaskService : Component, ISupportInitialize, System.
9697
private string userName;
9798
private bool userNameSet;
9899
private string userPassword;
100+
private SecureString userSecurePassword;
99101
private bool userPasswordSet;
100102
private WindowsImpersonatedIdentity v1Impersonation;
101103

@@ -130,6 +132,30 @@ public TaskService(string targetServer, string userName = null, string accountDo
130132
EndInit();
131133
}
132134

135+
/// <summary>Initializes a new instance of the <see cref="TaskService"/> class.</summary>
136+
/// <param name="targetServer">
137+
/// The name of the computer that you want to connect to. If the this parameter is empty, then this will connect to the local computer.
138+
/// </param>
139+
/// <param name="userName">
140+
/// The user name that is used during the connection to the computer. If the user is not specified, then the current token is used.
141+
/// </param>
142+
/// <param name="accountDomain">The domain of the user specified in the <paramref name="userName"/> parameter.</param>
143+
/// <param name="userSecurePassword">
144+
/// The password that is used to connect to the computer as a SecureString. If the user name and securePassword are not specified, then the current token is used.
145+
/// </param>
146+
/// <param name="forceV1">If set to <c>true</c> force Task Scheduler 1.0 compatibility.</param>
147+
public TaskService(string targetServer, string userName, string accountDomain, SecureString userSecurePassword, bool forceV1 = false)
148+
{
149+
BeginInit();
150+
TargetServer = targetServer;
151+
UserName = userName;
152+
UserAccountDomain = accountDomain;
153+
SetUserSecurePassword(userSecurePassword);
154+
this.forceV1 = forceV1;
155+
ResetHighestSupportedVersion();
156+
EndInit();
157+
}
158+
133159
private TaskService([NotNull] System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
134160
{
135161
BeginInit();
@@ -369,13 +395,38 @@ public string UserPassword
369395
if (value == null || value.Trim() == string.Empty) value = null;
370396
if (string.CompareOrdinal(value, userPassword) != 0)
371397
{
398+
userSecurePassword = null;
372399
userPasswordSet = true;
373400
userPassword = value;
374401
Connect();
375402
}
376403
}
377404
}
378405

406+
/// <summary>Gets the user password in plain text from either userPassword or userSecurePassword.</summary>
407+
internal string UserPasswordPlainText
408+
{
409+
get
410+
{
411+
if (!string.IsNullOrEmpty(userPassword))
412+
return userPassword;
413+
414+
if (userSecurePassword == null)
415+
return string.Empty;
416+
417+
IntPtr valuePtr = IntPtr.Zero;
418+
try
419+
{
420+
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(userSecurePassword);
421+
return Marshal.PtrToStringUni(valuePtr);
422+
}
423+
finally
424+
{
425+
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
426+
}
427+
}
428+
}
429+
379430
/// <summary>Gets a <see cref="IEnumerator{T}"/> which enumerates all the tasks in all folders.</summary>
380431
/// <value>A <see cref="IEnumerator{T}"/> for all <see cref="Task"/> instances.</value>
381432
[Browsable(false)]
@@ -575,7 +626,7 @@ public void EndInit()
575626
public override bool Equals(object obj)
576627
{
577628
if (obj is TaskService tsobj)
578-
return tsobj.TargetServer == TargetServer && tsobj.UserAccountDomain == UserAccountDomain && tsobj.UserName == UserName && tsobj.UserPassword == UserPassword && tsobj.forceV1 == forceV1;
629+
return tsobj.TargetServer == TargetServer && tsobj.UserAccountDomain == UserAccountDomain && tsobj.UserName == UserName && tsobj.UserPasswordPlainText == UserPasswordPlainText && tsobj.forceV1 == forceV1;
579630
return base.Equals(obj);
580631
}
581632

@@ -611,7 +662,7 @@ public Task FindTask([NotNull] string name, bool searchAllFolders = true)
611662
/// <summary>Gets the event log for this <see cref="TaskService"/> instance.</summary>
612663
/// <param name="taskPath">(Optional) The task path if only the events for a single task are desired.</param>
613664
/// <returns>A <see cref="TaskEventLog"/> instance.</returns>
614-
public TaskEventLog GetEventLog(string taskPath = null) => new(TargetServer, taskPath, UserAccountDomain, UserName, UserPassword);
665+
public TaskEventLog GetEventLog(string taskPath = null) => new(TargetServer, taskPath, UserAccountDomain, UserName, UserPasswordPlainText);
615666

616667
/// <summary>Gets the path to a folder of registered tasks.</summary>
617668
/// <param name="folderName">
@@ -647,7 +698,7 @@ public TaskFolder GetFolder(string folderName)
647698

648699
/// <summary>Returns a hash code for this instance.</summary>
649700
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
650-
public override int GetHashCode() => new { A = TargetServer, B = UserAccountDomain, C = UserName, D = UserPassword, E = forceV1 }.GetHashCode();
701+
public override int GetHashCode() => new { A = TargetServer, B = UserAccountDomain, C = UserName, D = UserPasswordPlainText, E = forceV1 }.GetHashCode();
651702

652703
/// <summary>Gets a collection of running tasks.</summary>
653704
/// <param name="includeHidden">True to include hidden tasks.</param>
@@ -711,6 +762,16 @@ public TaskDefinition NewTaskFromFile([NotNull] string xmlFile)
711762
return td;
712763
}
713764

765+
/// <summary>Sets the user password as a secure string to be used when connecting to the <see cref="TargetServer"/>.</summary>
766+
/// <param name="value">A secure string containing the user password to set.</param>
767+
public void SetUserSecurePassword(SecureString value)
768+
{
769+
userPasswordSet = true;
770+
userPassword = null;
771+
userSecurePassword = value;
772+
Connect();
773+
}
774+
714775
/// <summary>Starts the Task Scheduler UI for the OS hosting the assembly if the session is running in interactive mode.</summary>
715776
public void StartSystemTaskSchedulerManager()
716777
{
@@ -846,7 +907,7 @@ private void Connect()
846907

847908
if (!initializing && !DesignMode)
848909
{
849-
if (!string.IsNullOrEmpty(userDomain) && !string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userPassword) || string.IsNullOrEmpty(userDomain) && string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(userPassword))
910+
if (!string.IsNullOrEmpty(userDomain) && !string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(UserPasswordPlainText) || string.IsNullOrEmpty(userDomain) && string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(UserPasswordPlainText))
850911
{
851912
// Clear stuff if already connected
852913
connecting = true;
@@ -866,15 +927,15 @@ private void Connect()
866927
}
867928
else
868929
targetServer = null;
869-
v2TaskService.Connect(targetServer, userName, userDomain, userPassword);
930+
v2TaskService.Connect(targetServer, userName, userDomain, UserPasswordPlainText);
870931
targetServer = v2TaskService.TargetServer;
871932
userName = v2TaskService.ConnectedUser;
872933
userDomain = v2TaskService.ConnectedDomain;
873934
maxVer = GetV2Version();
874935
}
875936
else
876937
{
877-
v1Impersonation = new WindowsImpersonatedIdentity(userName, userDomain, userPassword);
938+
v1Impersonation = new WindowsImpersonatedIdentity(userName, userDomain, UserPasswordPlainText);
878939
v1TaskScheduler = new V1Interop.ITaskScheduler();
879940
if (!string.IsNullOrEmpty(targetServer))
880941
{
@@ -929,7 +990,11 @@ private void ResetUnsetProperties()
929990
if (!targetServerSet) targetServer = null;
930991
if (!userDomainSet) userDomain = null;
931992
if (!userNameSet) userName = null;
932-
if (!userPasswordSet) userPassword = null;
993+
if (!userPasswordSet)
994+
{
995+
userPassword = null;
996+
userSecurePassword = null;
997+
}
933998
}
934999

9351000
private bool ShouldSerializeHighestSupportedVersion() => LibraryIsV2 && maxVer <= TaskServiceVersion.V1_1;

0 commit comments

Comments
 (0)