From e76e097627a171302fdccd13fbd6eb31b51cd7ce Mon Sep 17 00:00:00 2001 From: makikvues Date: Tue, 19 Jan 2021 23:56:26 +0100 Subject: [PATCH] - refactoring & cleanup - updated Autorun checks --- .../winPEAS/Checks/ApplicationsInfo.cs | 2 +- .../winPEAS/Info/ApplicationInfo/AutoRuns.cs | 425 ++-- .../winPEAS/KnownFileCreds/Vault/VaultCli.cs | 2 +- .../Vault/structs/VAULT_ITEM_ELEMENT.cs | 2 +- .../Vault/structs/VAULT_ITEM_WIN7.cs | 2 +- .../Vault/structs/VAULT_ITEM_WIN8.cs | 2 +- .../winPEAS/TaskScheduler/Action.cs | 1924 +++++++++-------- .../winPEAS/TaskScheduler/ActionCollection.cs | 60 +- .../TaskScheduler/NamedValueCollection.cs | 2 +- .../winPEASexe/winPEAS/TaskScheduler/Task.cs | 31 +- .../winPEAS/TaskScheduler/TaskCollection.cs | 30 +- .../winPEAS/TaskScheduler/TaskFolder.cs | 4 +- .../TaskScheduler/TaskFolderCollection.cs | 7 +- .../winPEAS/TaskScheduler/TaskService.cs | 24 +- .../winPEAS/TaskScheduler/Trigger.cs | 69 +- .../TaskScheduler/TriggerCollection.cs | 19 +- .../V1/TaskSchedulerV1Interop.cs | 6 +- .../V2/TaskSchedulerV2Interop.cs | 7 +- 18 files changed, 1403 insertions(+), 1215 deletions(-) diff --git a/winPEAS/winPEASexe/winPEAS/Checks/ApplicationsInfo.cs b/winPEAS/winPEASexe/winPEAS/Checks/ApplicationsInfo.cs index 0065467..4fe3fec 100644 --- a/winPEAS/winPEASexe/winPEAS/Checks/ApplicationsInfo.cs +++ b/winPEAS/winPEASexe/winPEAS/Checks/ApplicationsInfo.cs @@ -103,7 +103,7 @@ namespace winPEAS.Checks { Beaprint.MainPrint("Autorun Applications"); Beaprint.LinkPrint("https://book.hacktricks.xyz/windows/windows-local-privilege-escalation/privilege-escalation-with-autorun-binaries", "Check if you can modify other users AutoRuns binaries (Note that is normal that you can modify HKCU registry and binaries indicated there)"); - List> apps = AutoRuns.GetAutoRuns(winPEAS.Checks.Checks.CurrentUserSiDs); + List> apps = AutoRuns.GetAutoRuns(Checks.CurrentUserSiDs); foreach (Dictionary app in apps) { diff --git a/winPEAS/winPEASexe/winPEAS/Info/ApplicationInfo/AutoRuns.cs b/winPEAS/winPEASexe/winPEAS/Info/ApplicationInfo/AutoRuns.cs index dc14ef7..7c16ffc 100644 --- a/winPEAS/winPEASexe/winPEAS/Info/ApplicationInfo/AutoRuns.cs +++ b/winPEAS/winPEASexe/winPEAS/Info/ApplicationInfo/AutoRuns.cs @@ -16,17 +16,164 @@ namespace winPEAS.Info.ApplicationInfo var result = new List>(); var regAutoRuns = GetRegistryAutoRuns(NtAccountNames); var folderAutoRuns = GetAutoRunsFolder(); - //var fileAutoRuns = GetAutoRunsFiles(); + var fileAutoRuns = GetAutoRunsFiles(); var wmicAutoRuns = GetAutoRunsWMIC(); result.AddRange(regAutoRuns); result.AddRange(folderAutoRuns); - //result.AddRange(fileAutoRuns); + result.AddRange(fileAutoRuns); result.AddRange(wmicAutoRuns); return result; } + private static List> autorunLocations = new List>() + { + //Common Autoruns + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\Run"}, + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunOnce"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"}, + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run"}, + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Runonce"}, + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunEx"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Run"}, + new List {"HKCU", @"Software\Microsoft\Windows NT\CurrentVersion\Windows\Run"}, + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunOnce"}, + new List {"HKCU", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"}, + new List {"HKCU", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"}, + + //Service Autoruns + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunService"}, + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunOnceService"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunService"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceService"}, + new List {"HKLM", @"System\CurrentControlSet\Services"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunService"}, + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunOnceService"}, + new List {"HKCU", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunService"}, + new List {"HKCU", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceService"}, + + //Special Autorun + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunOnceEx"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunOnceEx"}, + new List {"HKCU", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnceEx"}, + + //RunServices + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunServices"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunServices"}, + + //RunServicesOnce + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\RunServicesOnce"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\RunServicesOnce"}, + + //Startup Path + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", "Common Startup"}, + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", "Common Startup"}, + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", "Common Startup"}, + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", "Common Startup"}, + + + //Winlogon + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit"}, // key = Winlogo, Value = Userinit + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell"}, + + new List {"HKCU", @"Software\Microsoft\Windows NT\CurrentVersion\Windows", "load"}, + + //Policy Settings + new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "Run"}, // key = Explorer, Value = Run + + new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "Run"}, + + //AlternateShell in SafeBoot + new List {"HKLM", @"SYSTEM\CurrentControlSet\Control\SafeBoot", "AlternateShell"}, + + //Font Drivers + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Font Drivers"}, + new List {"HKLM", @"Software\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Font Drivers"}, + new List {"HKLM", @"Software\Microsoft\Windows NT\CurrentVersion\Drivers32"}, + new List {"HKLM", @"Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Drivers32"}, + + //Open Command + new List {"HKLM", @"Software\Classes\htmlfile\shell\open\command", ""}, //Get (Default) value with empty string + new List {"HKLM", @"Software\Wow6432Node\Classes\htmlfile\shell\open\command", ""}, //Get (Default) value with empty string + + // undocumented + new List { "HKLM", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler"}, + new List { "HKLM", @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler"}, + + // Misc Startup keys + new List { "HKLM", @"System\CurrentControlSet\Control\Session Manager\KnownDlls" }, + //new List { "HKCU", @"Control Panel\Desktop\scrnsave.exe" }, ??? + }; + + private static List> autorunLocationsKeys = new List> + { + //Installed Components + new List { "HKLM", @"Software\Microsoft\Active Setup\Installed Components", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Microsoft\Active Setup\Installed Components", "StubPath"}, + + new List { "HKCU", @"Software\Microsoft\Active Setup\Installed Components", "StubPath"}, + new List { "HKCU", @"Software\Wow6432Node\Microsoft\Active Setup\Installed Components", "StubPath"}, + + // Shell related autostart entries, e.g. items displayed when you right-click on files or folders. + new List { "HKLM", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects", "StubPath"}, + new List { "HKLM", @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects", "StubPath"}, + new List { "HKLM", @"SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad", "StubPath"}, + new List { "HKLM", @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad", "StubPath"}, + new List { "HKCU", @"Software\Classes\*\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\*\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKCU", @"Software\Classes\Drive\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Drive\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\*\ShellEx\PropertySheetHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\*\ShellEx\PropertySheetHandlers", "StubPath"}, + new List { "HKCU", @"Software\Classes\Directory\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Directory\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Directory\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKCU", @"Software\Classes\Directory\Shellex\DragDropHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Directory\Shellex\DragDropHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Directory\Shellex\DragDropHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Directory\Shellex\CopyHookHandlers", "StubPath"}, + new List { "HKCU", @"Software\Classes\Directory\Background\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Directory\Background\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Directory\Background\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Folder\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Folder\ShellEx\ContextMenuHandlers", "StubPath"}, + new List { "HKLM", @"Software\Classes\Folder\ShellEx\DragDropHandlers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\Folder\ShellEx\DragDropHandlers", "StubPath"}, + new List { "HKLM", @"Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers", "StubPath"}, + + // Misc Startup keys + new List { "HKLM", @"Software\Classes\Filter", "StubPath"}, + new List { "HKLM", @"Software\Classes\CLSID\{083863F1-70DE-11d0-BD40-00A0C911CE86}\Instance", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\CLSID\{083863F1-70DE-11d0-BD40-00A0C911CE86}\Instance", "StubPath"}, + new List { "HKLM", @"Software\Classes\CLSID\{7ED96837-96F0-4812-B211-F13C24117ED3}\Instance", "StubPath"}, + new List { "HKLM", @"Software\Wow6432Node\Classes\CLSID\{7ED96837-96F0-4812-B211-F13C24117ED3}\Instance", "StubPath"}, + new List { "HKLM", @"System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries", "StubPath"}, + new List { "HKLM", @"System\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries64", "StubPath"}, + }; + + + //This registry expect subkeys with the CLSID name + private static List> autorunLocationsKeysCLSIDs = new List> + { + //Browser Helper Objects + new List { "HKLM", @"Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects" }, + new List { "HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects" }, + + //Internet Explorer Extensions + new List { "HKLM", @"Software\Microsoft\Internet Explorer\Extensions" }, + new List { "HKLM", @"Software\Wow6432Node\Microsoft\Internet Explorer\Extensions" }, + }; + ////////////////////////////////////// /////// Get Autorun Registry //////// ////////////////////////////////////// @@ -36,92 +183,6 @@ namespace winPEAS.Info.ApplicationInfo List> results = new List>(); try { - List> autorunLocations = new List>() - { - //Common Autoruns - new List {"HKLM","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"}, - new List {"HKLM","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"}, - new List {"HKLM","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run"}, - new List {"HKLM","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce"}, - new List {"HKCU","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"}, - new List {"HKCU","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"}, - new List {"HKCU","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run"}, - new List {"HKCU","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce"}, - new List {"HKLM",@"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Run"}, - new List {"HKLM",@"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\Runonce"}, - new List {"HKLM",@"Software\Microsoft\Windows NT\CurrentVersion\Terminal Server\Install\Software\Microsoft\Windows\CurrentVersion\RunEx"}, - - //Service Autoruns - new List {"HKLM","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunService"}, - new List {"HKLM","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnceService"}, - new List {"HKLM","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunService"}, - new List {"HKLM","SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceService"}, - new List {"HKCU", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunService"}, - new List {"HKCU", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnceService"}, - new List {"HKCU", "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunService"}, - new List {"HKCU", "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceService"}, - - //Special Autorun - new List {"HKLM","Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"}, - new List {"HKLM","Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"}, - new List {"HKCU","Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"}, - new List {"HKCU","Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx"}, - - //RunServicesOnce - new List {"HKCU","Software\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce"}, - new List {"HKLM","SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce"}, - - //Startup Path - new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", "Common Startup"}, - new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", "Common Startup"}, - new List {"HKLM", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", "Common Startup"}, - new List {"HKLM", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders", "Common Startup"}, - - //Winlogon - new List {"HKLM", @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Userinit"}, - new List {"HKLM", @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell"}, - - new List { "HKCU", @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows", "load"}, - - //Policy Settings - new List {"HKLM", @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "Run"}, - new List {"HKCU", @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", "Run"}, - - //AlternateShell in SafeBoot - new List {"HKLM","SYSTEM\\CurrentControlSet\\Control\\SafeBoot", "AlternateShell"}, - - //Font Drivers - new List {"HKLM", @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Font Drivers"}, - new List {"HKLM", @"SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Font Drivers"}, - - //Open Command - new List {"HKLM", @"SOFTWARE\Classes\htmlfile\shell\open\command", ""}, //Get (Default) value with empty string - new List {"HKLM", @"SOFTWARE\Wow6432Node\Classes\htmlfile\shell\open\command", ""}, //Get (Default) value with empty string - - }; - - List> autorunLocationsKeys = new List> - { - //Installed Components - new List { "HKLM","SOFTWARE\\Microsoft\\Active Setup\\Installed Components", "StubPath"}, - new List { "HKLM","SOFTWARE\\Wow6432Node\\Microsoft\\Active Setup\\Installed Components", "StubPath"}, - new List { "HKCU","SOFTWARE\\Microsoft\\Active Setup\\Installed Components", "StubPath"}, - new List { "HKCU","SOFTWARE\\Wow6432Node\\Microsoft\\Active Setup\\Installed Components", "StubPath"}, - }; - - - //This registry expect subkeys with the CLSID name - List> autorunLocationsKeysCLSIDs = new List> - { - //Browser Helper Objects - new List { "HKLM", @"Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects" }, - new List { "HKLM", @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects" }, - - //Internet Explorer Extensions - new List { "HKLM", @"Software\Microsoft\Internet Explorer\Extensions" }, - new List { "HKLM", @"Software\Wow6432Node\Microsoft\Internet Explorer\Extensions" }, - }; - //Add the keyvalues inside autorunLocationsKeys to autorunLocations foreach (List autorunLocationKey in autorunLocationsKeys) { @@ -154,25 +215,36 @@ namespace winPEAS.Info.ApplicationInfo { RegistryKey key = null; if ("HKLM" == autorunLocation[0]) + { key = Registry.LocalMachine.OpenSubKey(autorunLocation[1]); + } else + { key = Registry.CurrentUser.OpenSubKey(autorunLocation[1]); - + } if (autorunLocation.Count > 2 && kvp.Key != autorunLocation[2]) + { continue; //If only interested on 1 key of the registry and it's that one, continue + } string orig_filepath = Environment.ExpandEnvironmentVariables(string.Format("{0}", kvp.Value)); string filepath = orig_filepath; - if (MyUtils.GetExecutableFromPath(Environment.ExpandEnvironmentVariables(string.Format("{0}", kvp.Value))).Length > 0) - filepath = MyUtils.GetExecutableFromPath(filepath); - string filepath_cleaned = filepath.Replace("'", "").Replace("\"", ""); - string folder = System.IO.Path.GetDirectoryName(filepath_cleaned); + if (MyUtils.GetExecutableFromPath(Environment.ExpandEnvironmentVariables(string.Format("{0}", kvp.Value))).Length > 0) + { + filepath = MyUtils.GetExecutableFromPath(filepath); + } + + string filepath_cleaned = filepath.Replace("'", "").Replace("\"", ""); + string folder = Path.GetDirectoryName(filepath_cleaned); + try - { //If the path doesn't exist, pass + { + //If the path doesn't exist, pass if (File.GetAttributes(filepath_cleaned).HasFlag(FileAttributes.Directory)) - { //If the path is already a folder, change the values of the params + { + //If the path is already a folder, change the values of the params orig_filepath = ""; folder = filepath_cleaned; } @@ -222,7 +294,7 @@ namespace winPEAS.Info.ApplicationInfo if (string.IsNullOrEmpty(orig_filepath)) continue; orig_filepath = Environment.ExpandEnvironmentVariables(orig_filepath).Replace("'", "").Replace("\"", ""); - string folder = System.IO.Path.GetDirectoryName(orig_filepath); + string folder = Path.GetDirectoryName(orig_filepath); results.Add(new Dictionary() { @@ -257,14 +329,16 @@ namespace winPEAS.Info.ApplicationInfo private static IEnumerable> GetAutoRunsFolder() { List> results = new List>(); - List autorunLocations = new List(); - // displays startup for current user - //autorunLocations.Add(Environment.ExpandEnvironmentVariables(@"%appdata%\Microsoft\Windows\Start Menu\Programs\Startup")); - autorunLocations.Add(Environment.ExpandEnvironmentVariables(@"%programdata%\Microsoft\Windows\Start Menu\Programs\Startup")); - //string usersPath = Environment.GetEnvironmentVariable("USERPROFILE") + "\\..\\"; + var systemDrive = Environment.GetEnvironmentVariable("SystemDrive"); + var autorunLocations = new List + { + Environment.ExpandEnvironmentVariables(@"%programdata%\Microsoft\Windows\Start Menu\Programs\Startup"), + }; + string usersPath = Path.Combine(Environment.GetEnvironmentVariable(@"USERPROFILE")); usersPath = Directory.GetParent(usersPath).FullName; + try { var userDirs = Directory.GetDirectories(usersPath); @@ -285,10 +359,14 @@ namespace winPEAS.Info.ApplicationInfo foreach (string path in autorunLocations) { - foreach (string filepath in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)) + try { - string folder = Path.GetDirectoryName(filepath); - results.Add(new Dictionary() { + var files = Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly); + + foreach (string filepath in files) + { + string folder = Path.GetDirectoryName(filepath); + results.Add(new Dictionary() { { "Reg", "" }, { "RegKey", "" }, { "RegPermissions", "" }, @@ -298,46 +376,91 @@ namespace winPEAS.Info.ApplicationInfo { "interestingFolderRights", string.Join(", ", PermissionsHelper.GetPermissionsFolder(folder, Checks.Checks.CurrentUserSiDs))}, { "interestingFileRights", string.Join(", ", PermissionsHelper.GetPermissionsFile(filepath, Checks.Checks.CurrentUserSiDs))}, { "isUnquotedSpaced", "" } - }); + }); + } + } + catch (Exception e) + { } } + + var taskAutorunLocations = new HashSet() + { + $"{systemDrive}\\windows\\tasks", + $"{systemDrive}\\windows\\system32\\tasks", + }; + + foreach (string folder in taskAutorunLocations) + { + try + { + results.Add(new Dictionary() { + { "Reg", "" }, + { "RegKey", "" }, + { "RegPermissions", "" }, + { "Folder", folder }, + { "File", "" }, + { "isWritableReg", ""}, + { "interestingFolderRights", string.Join(", ", PermissionsHelper.GetPermissionsFolder(folder, Checks.Checks.CurrentUserSiDs))}, + { "interestingFileRights", ""}, + { "isUnquotedSpaced", "" } + }); + } + catch (Exception e) + { + } + } + return results; } private static IEnumerable> GetAutoRunsWMIC() { var results = new List>(); - try { SelectQuery query = new SelectQuery("Win32_StartupCommand"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); - ManagementObjectCollection win32_startup = searcher.Get(); - foreach (ManagementObject startup in win32_startup) + + using (ManagementObjectCollection win32_startup = searcher.Get()) { - string command = startup["command"].ToString(); - command = Environment.ExpandEnvironmentVariables(string.Format("{0}", command)); - string filepath = MyUtils.GetExecutableFromPath(command); - string filepath_cleaned = filepath.Replace("'", "").Replace("\"", ""); - string folder = System.IO.Path.GetDirectoryName(filepath_cleaned); - results.Add(new Dictionary() + foreach (ManagementObject startup in win32_startup) { - {"Reg", ""}, - {"RegKey", "From WMIC"}, - {"RegPermissions", ""}, - {"Folder", folder}, - {"File", command}, - {"isWritableReg", ""}, + string command = startup["command"].ToString(); + command = Environment.ExpandEnvironmentVariables(string.Format("{0}", command)); + string filepath = MyUtils.GetExecutableFromPath(command); + + if (!string.IsNullOrEmpty(filepath)) { - "interestingFolderRights", - string.Join(", ", PermissionsHelper.GetPermissionsFolder(folder, Checks.Checks.CurrentUserSiDs)) - }, - { - "interestingFileRights", - string.Join(", ", PermissionsHelper.GetPermissionsFile(filepath, Checks.Checks.CurrentUserSiDs)) - }, - {"isUnquotedSpaced", MyUtils.CheckQuoteAndSpace(command).ToString()} - }); + string filepathCleaned = filepath.Replace("'", "").Replace("\"", ""); + + try + { + string folder = Path.GetDirectoryName(filepathCleaned); + results.Add(new Dictionary() + { + {"Reg", ""}, + {"RegKey", "From WMIC"}, + {"RegPermissions", ""}, + {"Folder", folder}, + {"File", command}, + {"isWritableReg", ""}, + { + "interestingFolderRights", + string.Join(", ", PermissionsHelper.GetPermissionsFolder(folder, Checks.Checks.CurrentUserSiDs)) + }, + { + "interestingFileRights", + string.Join(", ", PermissionsHelper.GetPermissionsFile(filepath, Checks.Checks.CurrentUserSiDs)) + }, + {"isUnquotedSpaced", MyUtils.CheckQuoteAndSpace(command).ToString()} + }); + } + catch (Exception) + { + } + } + } } } catch (Exception e) @@ -349,7 +472,49 @@ namespace winPEAS.Info.ApplicationInfo private static IEnumerable> GetAutoRunsFiles() { - throw new NotImplementedException(); + var results = new List>(); + var systemDrive = Environment.GetEnvironmentVariable("SystemDrive"); + var autostartFiles = new HashSet + { + $"{systemDrive}\\autoexec.bat", + $"{systemDrive}\\config.sys", + $"{systemDrive}\\windows\\winstart.bat", + $"{systemDrive}\\windows\\wininit.ini", + $"{systemDrive}\\windows\\dosstart.bat", + $"{systemDrive}\\windows\\system.ini", + $"{systemDrive}\\windows\\win.ini", + $"{systemDrive}\\windows\\system\\autoexec.nt", + $"{systemDrive}\\windows\\system\\config.nt" + }; + + foreach (string path in autostartFiles) + { + try + { + if (File.Exists(path)) + { + string folder = Path.GetDirectoryName(path); + + results.Add(new Dictionary + { + { "Reg", "" }, + { "RegKey", "" }, + { "RegPermissions", "" }, + { "Folder", folder }, + { "File", path }, + { "isWritableReg", ""}, + { "interestingFolderRights", string.Join(", ", PermissionsHelper.GetPermissionsFolder(folder, Checks.Checks.CurrentUserSiDs))}, + { "interestingFileRights", string.Join(", ", PermissionsHelper.GetPermissionsFile(path, Checks.Checks.CurrentUserSiDs))}, + { "isUnquotedSpaced", "" } + }); + } + } + catch (Exception e) + { + } + } + + return results; } } } diff --git a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/VaultCli.cs b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/VaultCli.cs index 51ed395..e9c6ec0 100644 --- a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/VaultCli.cs +++ b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/VaultCli.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using winPEAS.Helpers; -using winPEAS.KnownFileCreds.Vault.structs; +using winPEAS.KnownFileCreds.Vault.Structs; namespace winPEAS.KnownFileCreds.Vault { diff --git a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_ELEMENT.cs b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_ELEMENT.cs index d9ae012..91c55a7 100644 --- a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_ELEMENT.cs +++ b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_ELEMENT.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; using winPEAS.KnownFileCreds.Vault.Enums; -namespace winPEAS.KnownFileCreds.Vault.structs +namespace winPEAS.KnownFileCreds.Vault.Structs { [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] public struct VAULT_ITEM_ELEMENT diff --git a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN7.cs b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN7.cs index 877eeed..eedf4ff 100644 --- a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN7.cs +++ b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN7.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace winPEAS.KnownFileCreds.Vault.structs +namespace winPEAS.KnownFileCreds.Vault.Structs { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct VAULT_ITEM_WIN7 diff --git a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN8.cs b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN8.cs index 94b2240..74c667d 100644 --- a/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN8.cs +++ b/winPEAS/winPEASexe/winPEAS/KnownFileCreds/Vault/structs/VAULT_ITEM_WIN8.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace winPEAS.KnownFileCreds.Vault.structs +namespace winPEAS.KnownFileCreds.Vault.Structs { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct VAULT_ITEM_WIN8 diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Action.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Action.cs index 8d6877c..5cd05fe 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Action.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Action.cs @@ -1,660 +1,667 @@ -using Microsoft.Win32; -using System; +using System; using System.Collections.Generic; using System.ComponentModel; -using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using System.Xml.Serialization; -using winPEAS.TaskScheduler.V2Interop; +using Microsoft.Win32; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { - /// Defines the type of actions a task can perform. - /// The action type is defined when the action is created and cannot be changed later. See . - public enum TaskActionType - { - /// - /// This action performs a command-line operation. For example, the action can run a script, launch an executable, or, if the name - /// of a document is provided, find its associated application and launch the application with the document. - /// - Execute = 0, - - /// This action fires a handler. - ComHandler = 5, - - /// This action sends and e-mail. - SendEmail = 6, - - /// This action shows a message box. - ShowMessage = 7 - } - - /// An interface that exposes the ability to convert an actions functionality to a PowerShell script. - internal interface IBindAsExecAction - { - } - - /// - /// Abstract base class that provides the common properties that are inherited by all action objects. An action object is created by the - /// method. - /// - [PublicAPI] - public abstract class Action : IDisposable, ICloneable, IEquatable, INotifyPropertyChanged, IComparable, IComparable - { - internal IAction iAction; - internal V1Interop.ITask v1Task; - - /// List of unbound values when working with Actions not associated with a registered task. - protected readonly Dictionary unboundValues = new Dictionary(); - - internal Action() - { - } - - internal Action([NotNull] IAction action) => iAction = action; - - internal Action([NotNull] V1Interop.ITask iTask) => v1Task = iTask; - - /// Occurs when a property value changes. - public event PropertyChangedEventHandler PropertyChanged; - - /// Gets the type of the action. - /// The type of the action. - [XmlIgnore] - public TaskActionType ActionType => iAction?.Type ?? InternalActionType; - - /// Gets or sets the identifier of the action. - [DefaultValue(null)] - [XmlAttribute(AttributeName = "id")] - public virtual string Id - { - get => GetProperty(nameof(Id)); - set => SetProperty(nameof(Id), value); - } - - internal abstract TaskActionType InternalActionType { get; } - - /// Creates the specified action. - /// Type of the action to instantiate. - /// of specified type. - public static Action CreateAction(TaskActionType actionType) => Activator.CreateInstance(GetObjectType(actionType)) as Action; - - /// Creates a new object that is a copy of the current instance. - /// A new object that is a copy of this instance. - public object Clone() - { - var ret = CreateAction(ActionType); - ret.CopyProperties(this); - return ret; - } - - /// - /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current - /// instance precedes, follows, or occurs in the same position in the sort order as the other object. - /// - /// An object to compare with this instance. - /// A value that indicates the relative order of the objects being compared. - public int CompareTo(Action obj) => string.Compare(Id, obj?.Id, StringComparison.InvariantCulture); - - /// Releases all resources used by this class. - public virtual void Dispose() - { - if (iAction != null) - Marshal.ReleaseComObject(iAction); - } - - /// Determines whether the specified , is equal to this instance. - /// The to compare with this instance. - /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals([CanBeNull] object obj) - { - if (obj is Action) - return Equals((Action)obj); - return base.Equals(obj); - } - - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// true if the current object is equal to the parameter; otherwise, false. - public virtual bool Equals([NotNull] Action other) => ActionType == other.ActionType && Id == other.Id; - - /// Returns a hash code for this instance. - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - public override int GetHashCode() => new { A = ActionType, B = Id }.GetHashCode(); - - /// Returns the action Id. - /// String representation of action. - public override string ToString() => Id; - - /// Returns a that represents this action. - /// The culture. - /// String representation of action. - public virtual string ToString([NotNull] System.Globalization.CultureInfo culture) - { - using (new CultureSwitcher(culture)) - return ToString(); - } - - int IComparable.CompareTo(object obj) => CompareTo(obj as Action); - - internal static Action ActionFromScript(string actionType, string script) - { - var tat = TryParse(actionType, TaskActionType.Execute); - var t = GetObjectType(tat); - return (Action)t.InvokeMember("FromPowerShellCommand", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { script }); - } - - internal static Action ConvertFromPowerShellAction(ExecAction execAction) - { - var psi = execAction.ParsePowerShellItems(); - if (psi != null && psi.Length == 2) - { - var a = ActionFromScript(psi[0], psi[1]); - if (a != null) - { - a.v1Task = execAction.v1Task; - a.iAction = execAction.iAction; - return a; - } - } - return null; - } - - /// Creates a specialized class from a defined interface. - /// Version 1.0 interface. - /// Specialized action class - internal static Action CreateAction(V1Interop.ITask iTask) - { - var tempAction = new ExecAction(iTask); - return ConvertFromPowerShellAction(tempAction) ?? tempAction; - } - - /// Creates a specialized class from a defined interface. - /// Version 2.0 Action interface. - /// Specialized action class - internal static Action CreateAction(IAction iAction) - { - var t = GetObjectType(iAction.Type); - return Activator.CreateInstance(t, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { iAction }, null) as Action; - } - - internal static T TryParse(string val, T defaultVal) - { - var ret = defaultVal; - if (val != null) - try { ret = (T)Enum.Parse(typeof(T), val); } catch { } - return ret; - } - - internal virtual void Bind(V1Interop.ITask iTask) - { - if (Id != null) - iTask.SetDataItem("ActionId", Id); - var bindable = this as IBindAsExecAction; - if (bindable != null) - iTask.SetDataItem("ActionType", InternalActionType.ToString()); - unboundValues.TryGetValue("Path", out var o); - iTask.SetApplicationName(bindable != null ? ExecAction.PowerShellPath : o?.ToString() ?? string.Empty); - unboundValues.TryGetValue("Arguments", out o); - iTask.SetParameters(bindable != null ? ExecAction.BuildPowerShellCmd(ActionType.ToString(), GetPowerShellCommand()) : o?.ToString() ?? string.Empty); - unboundValues.TryGetValue("WorkingDirectory", out o); - iTask.SetWorkingDirectory(o?.ToString() ?? string.Empty); - } - - internal virtual void Bind(ITaskDefinition iTaskDef) - { - var iActions = iTaskDef.Actions; - if (iActions.Count >= ActionCollection.MaxActions) - throw new ArgumentOutOfRangeException(nameof(iTaskDef), @"A maximum of 32 actions is allowed within a single task."); - CreateV2Action(iActions); - Marshal.ReleaseComObject(iActions); - foreach (var key in unboundValues.Keys) - { - try { ReflectionHelper.SetProperty(iAction, key, unboundValues[key]); } - catch (TargetInvocationException tie) { throw tie.InnerException; } - catch { } - } - unboundValues.Clear(); - } - - /// Copies the properties from another the current instance. - /// The source . - internal virtual void CopyProperties([NotNull] Action sourceAction) => Id = sourceAction.Id; - - internal abstract void CreateV2Action(IActionCollection iActions); - - internal abstract string GetPowerShellCommand(); - - internal T GetProperty(string propName, T defaultValue = default) - { - if (iAction == null) - return unboundValues.TryGetValue(propName, out var value) ? (T)value : defaultValue; - return ReflectionHelper.GetProperty((TB)iAction, propName, defaultValue); - } - - internal void OnPropertyChanged(string propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); - - internal void SetProperty(string propName, T value) - { - if (iAction == null) - { - if (Equals(value, default(T))) - unboundValues.Remove(propName); - else - unboundValues[propName] = value; - } - else - ReflectionHelper.SetProperty((TB)iAction, propName, value); - OnPropertyChanged(propName); - } - - [NotNull] - private static Type GetObjectType(TaskActionType actionType) => actionType switch - { - TaskActionType.ComHandler => typeof(ComHandlerAction), - TaskActionType.SendEmail => typeof(EmailAction), - TaskActionType.ShowMessage => typeof(ShowMessageAction), - _ => typeof(ExecAction), - }; - } - - /// - /// Represents an action that fires a handler. Only available on Task Scheduler 2.0. Only available for Task Scheduler 2.0 on - /// Windows Vista or Windows Server 2003 and later. - /// - /// - /// This action is the most complex. It allows the task to execute and In-Proc COM server object that implements the ITaskHandler - /// interface. There is a sample project that shows how to do this in the Downloads section. - /// - /// - /// - /// - /// - /// - [XmlType(IncludeInSchema = true)] - [XmlRoot("ComHandler", Namespace = TaskDefinition.tns, IsNullable = false)] - public class ComHandlerAction : Action, IBindAsExecAction - { - /// Creates an unbound instance of . - public ComHandlerAction() { } - - /// Creates an unbound instance of . - /// Identifier of the handler class. - /// Addition data associated with the handler. - public ComHandlerAction(Guid classId, [CanBeNull] string data) - { - ClassId = classId; - Data = data; - } - - internal ComHandlerAction([NotNull] V1Interop.ITask task) : base(task) - { - } - - internal ComHandlerAction([NotNull] IAction action) : base(action) - { - } - - /// Gets or sets the identifier of the handler class. - public Guid ClassId - { - get => new Guid(GetProperty(nameof(ClassId), Guid.Empty.ToString())); - set => SetProperty(nameof(ClassId), value.ToString()); - } - - /// Gets the name of the object referred to by . - public string ClassName => GetNameForCLSID(ClassId); - - /// Gets or sets additional data that is associated with the handler. - [DefaultValue(null)] - [CanBeNull] - public string Data - { - get => GetProperty(nameof(Data)); - set => SetProperty(nameof(Data), value); - } - - internal override TaskActionType InternalActionType => TaskActionType.ComHandler; - - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// true if the current object is equal to the parameter; otherwise, false. - public override bool Equals(Action other) => base.Equals(other) && ClassId == ((ComHandlerAction)other).ClassId && Data == ((ComHandlerAction)other).Data; - - /// Gets a string representation of the . - /// String representation of this action. - public override string ToString() => string.Format(Properties.Resources.ComHandlerAction, ClassId, Data, Id, ClassName); - - internal static Action FromPowerShellCommand(string p) - { - var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[Reflection.Assembly\]::LoadFile\('(?:[^']*)'\); \[Microsoft.Win32.TaskScheduler.TaskService\]::RunComHandlerAction\(\[GUID\]\('(?[^']*)'\), '(?[^']*)'\);?\s*$"); - return match.Success ? new ComHandlerAction(new Guid(match.Groups["g"].Value), match.Groups["d"].Value.Replace("''", "'")) : null; - } - - /// Copies the properties from another the current instance. - /// The source . - internal override void CopyProperties(Action sourceAction) - { - if (sourceAction.GetType() == GetType()) - { - base.CopyProperties(sourceAction); - ClassId = ((ComHandlerAction)sourceAction).ClassId; - Data = ((ComHandlerAction)sourceAction).Data; - } - } - - internal override void CreateV2Action([NotNull] IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ComHandler); - - internal override string GetPowerShellCommand() - { - var sb = new System.Text.StringBuilder(); - sb.Append($"[Reflection.Assembly]::LoadFile('{Assembly.GetExecutingAssembly().Location}'); "); - sb.Append($"[Microsoft.Win32.TaskScheduler.TaskService]::RunComHandlerAction([GUID]('{ClassId:D}'), '{Data?.Replace("'", "''") ?? string.Empty}'); "); - return sb.ToString(); - } - - /// Gets the name for CLSID. - /// The unique identifier. - /// - [CanBeNull] - private static string GetNameForCLSID(Guid guid) - { - using (var k = Registry.ClassesRoot.OpenSubKey("CLSID", false)) - { - if (k != null) - { - using var k2 = k.OpenSubKey(guid.ToString("B"), false); - return k2?.GetValue(null) as string; - } - } - return null; - } - } - - /// - /// Represents an action that sends an e-mail. Only available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and - /// later.This action has been deprecated in Windows 8 and later. However, this library is able to mimic its - /// functionality using PowerShell if the property is set to . To disable this conversion, set the value to . - /// - /// The EmailAction allows for an email to be sent when the task is triggered. - /// - /// - /// - /// - /// - [XmlType(IncludeInSchema = true)] - [XmlRoot("SendEmail", Namespace = TaskDefinition.tns, IsNullable = false)] - public sealed class EmailAction : Action, IBindAsExecAction - { - private const string ImportanceHeader = "Importance"; - - private NamedValueCollection nvc; - private bool validateAttachments = true; - - /// Creates an unbound instance of . - public EmailAction() { } - - /// Creates an unbound instance of . - /// Subject of the e-mail. - /// E-mail address that you want to send the e-mail from. - /// E-mail address or addresses that you want to send the e-mail to. - /// Body of the e-mail that contains the e-mail message. - /// Name of the server that you use to send e-mail from. - public EmailAction([CanBeNull] string subject, [NotNull] string from, [NotNull] string to, [CanBeNull] string body, [NotNull] string mailServer) - { - Subject = subject; - From = from; - To = to; - Body = body; - Server = mailServer; - } - - internal EmailAction([NotNull] V1Interop.ITask task) : base(task) - { - } - - internal EmailAction([NotNull] IAction action) : base(action) - { - } - - /// - /// Gets or sets an array of file paths to be sent as attachments with the e-mail. Each item must be a value - /// containing a path to file. - /// - [XmlArray("Attachments", IsNullable = true)] - [XmlArrayItem("File", typeof(string))] - [DefaultValue(null)] - public object[] Attachments - { - get => GetProperty(nameof(Attachments)); - set - { - if (value != null) - { - if (value.Length > 8) - throw new ArgumentOutOfRangeException(nameof(Attachments), @"Attachments array cannot contain more than 8 items."); - if (validateAttachments) - { - foreach (var o in value) - if (!(o is string) || !System.IO.File.Exists((string)o)) - throw new ArgumentException(@"Each value of the array must contain a valid file reference.", nameof(Attachments)); - } - } - if (iAction == null && (value == null || value.Length == 0)) - { - unboundValues.Remove(nameof(Attachments)); - OnPropertyChanged(nameof(Attachments)); - } - else - SetProperty(nameof(Attachments), value); - } - } - - /// Gets or sets the e-mail address or addresses that you want to Bcc in the e-mail. - [DefaultValue(null)] - public string Bcc - { - get => GetProperty(nameof(Bcc)); - set => SetProperty(nameof(Bcc), value); - } - - /// Gets or sets the body of the e-mail that contains the e-mail message. - [DefaultValue(null)] - public string Body - { - get => GetProperty(nameof(Body)); - set => SetProperty(nameof(Body), value); - } - - /// Gets or sets the e-mail address or addresses that you want to Cc in the e-mail. - [DefaultValue(null)] - public string Cc - { - get => GetProperty(nameof(Cc)); - set => SetProperty(nameof(Cc), value); - } - - /// Gets or sets the e-mail address that you want to send the e-mail from. - [DefaultValue(null)] - public string From - { - get => GetProperty(nameof(From)); - set => SetProperty(nameof(From), value); - } - - /// Gets or sets the header information in the e-mail message to send. - [XmlArray] - [XmlArrayItem("HeaderField", typeof(NameValuePair))] - [NotNull] - public NamedValueCollection HeaderFields - { - get - { - if (nvc == null) - { - nvc = iAction == null ? new NamedValueCollection() : new NamedValueCollection(((IEmailAction)iAction).HeaderFields); - nvc.AttributedXmlFormat = false; - nvc.CollectionChanged += (o, e) => OnPropertyChanged(nameof(HeaderFields)); - } - return nvc; - } - } - - /// Gets or sets the priority of the e-mail message. - /// A that contains the priority of this message. - [XmlIgnore] - [DefaultValue(typeof(System.Net.Mail.MailPriority), "Normal")] - public System.Net.Mail.MailPriority Priority - { - get - { - if (nvc != null && HeaderFields.TryGetValue(ImportanceHeader, out var s)) - return TryParse(s, System.Net.Mail.MailPriority.Normal); - return System.Net.Mail.MailPriority.Normal; - } - set => HeaderFields[ImportanceHeader] = value.ToString(); - } - - /// Gets or sets the e-mail address that you want to reply to. - [DefaultValue(null)] - public string ReplyTo - { - get => GetProperty(nameof(ReplyTo)); - set => SetProperty(nameof(ReplyTo), value); - } - - /// Gets or sets the name of the server that you use to send e-mail from. - [DefaultValue(null)] - public string Server - { - get => GetProperty(nameof(Server)); - set => SetProperty(nameof(Server), value); - } - - /// Gets or sets the subject of the e-mail. - [DefaultValue(null)] - public string Subject - { - get => GetProperty(nameof(Subject)); - set => SetProperty(nameof(Subject), value); - } - - /// Gets or sets the e-mail address or addresses that you want to send the e-mail to. - [DefaultValue(null)] - public string To - { - get => GetProperty(nameof(To)); - set => SetProperty(nameof(To), value); - } - - internal override TaskActionType InternalActionType => TaskActionType.SendEmail; - - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// true if the current object is equal to the parameter; otherwise, false. - public override bool Equals(Action other) => base.Equals(other) && GetPowerShellCommand() == other.GetPowerShellCommand(); - - /// Gets a string representation of the . - /// String representation of this action. - public override string ToString() => string.Format(Properties.Resources.EmailAction, Subject, To, Cc, Bcc, From, ReplyTo, Body, Server, Id); - - internal static Action FromPowerShellCommand(string p) - { - var match = System.Text.RegularExpressions.Regex.Match(p, @"^Send-MailMessage -From '(?(?:[^']|'')*)' -Subject '(?(?:[^']|'')*)' -SmtpServer '(?(?:[^']|'')*)'(?: -Encoding UTF8)?(?: -To (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Cc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Bcc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?:(?: -BodyAsHtml)? -Body '(?(?:[^']|'')*)')?(?: -Attachments (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Priority (?High|Normal|Low))?;?\s*$"); - if (match.Success) - { - var action = new EmailAction(UnPrep(FromUTF8(match.Groups["subject"].Value)), UnPrep(match.Groups["from"].Value), FromPS(match.Groups["to"]), UnPrep(FromUTF8(match.Groups["body"].Value)), UnPrep(match.Groups["server"].Value)) - { Cc = FromPS(match.Groups["cc"]), Bcc = FromPS(match.Groups["bcc"]) }; - action.validateAttachments = false; - if (match.Groups["att"].Success) - action.Attachments = Array.ConvertAll(FromPS(match.Groups["att"].Value), s => s); - action.validateAttachments = true; - if (match.Groups["imp"].Success) - action.HeaderFields[ImportanceHeader] = match.Groups["imp"].Value; - return action; - } - return null; - } - - internal override void Bind(ITaskDefinition iTaskDef) - { - base.Bind(iTaskDef); - nvc?.Bind(((IEmailAction)iAction).HeaderFields); - } - - /// Copies the properties from another the current instance. - /// The source . - internal override void CopyProperties(Action sourceAction) - { - if (sourceAction.GetType() == GetType()) - { - base.CopyProperties(sourceAction); - if (((EmailAction)sourceAction).Attachments != null) - Attachments = (object[])((EmailAction)sourceAction).Attachments.Clone(); - Bcc = ((EmailAction)sourceAction).Bcc; - Body = ((EmailAction)sourceAction).Body; - Cc = ((EmailAction)sourceAction).Cc; - From = ((EmailAction)sourceAction).From; - if (((EmailAction)sourceAction).nvc != null) - ((EmailAction)sourceAction).HeaderFields.CopyTo(HeaderFields); - ReplyTo = ((EmailAction)sourceAction).ReplyTo; - Server = ((EmailAction)sourceAction).Server; - Subject = ((EmailAction)sourceAction).Subject; - To = ((EmailAction)sourceAction).To; - } - } - - internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.SendEmail); - - internal override string GetPowerShellCommand() - { - // Send-MailMessage [-To] [-Subject] [[-Body] ] [[-SmtpServer] ] -From - // [-Attachments ] [-Bcc ] [-BodyAsHtml] [-Cc ] [-Credential ] - // [-DeliveryNotificationOption ] [-Encoding ] [-Port ] [-Priority - // ] [-UseSsl] [ ] - var bodyIsHtml = Body != null && Body.Trim().StartsWith("<") && Body.Trim().EndsWith(">"); - var sb = new System.Text.StringBuilder(); - sb.AppendFormat("Send-MailMessage -From '{0}' -Subject '{1}' -SmtpServer '{2}' -Encoding UTF8", Prep(From), ToUTF8(Prep(Subject)), Prep(Server)); - if (!string.IsNullOrEmpty(To)) - sb.AppendFormat(" -To {0}", ToPS(To)); - if (!string.IsNullOrEmpty(Cc)) - sb.AppendFormat(" -Cc {0}", ToPS(Cc)); - if (!string.IsNullOrEmpty(Bcc)) - sb.AppendFormat(" -Bcc {0}", ToPS(Bcc)); - if (bodyIsHtml) - sb.Append(" -BodyAsHtml"); - if (!string.IsNullOrEmpty(Body)) - sb.AppendFormat(" -Body '{0}'", ToUTF8(Prep(Body))); - if (Attachments != null && Attachments.Length > 0) - sb.AppendFormat(" -Attachments {0}", ToPS(Array.ConvertAll(Attachments, o => Prep(o.ToString())))); - var hdr = new List(HeaderFields.Names); - if (hdr.Contains(ImportanceHeader)) - { - var p = Priority; - if (p != System.Net.Mail.MailPriority.Normal) - sb.Append($" -Priority {p}"); - hdr.Remove(ImportanceHeader); - } - if (hdr.Count > 0) - throw new InvalidOperationException("Under Windows 8 and later, EmailAction objects are converted to PowerShell. This action contains headers that are not supported."); - sb.Append("; "); - return sb.ToString(); - - /*var msg = new System.Net.Mail.MailMessage(this.From, this.To, this.Subject, this.Body); + /// Defines the type of actions a task can perform. + /// The action type is defined when the action is created and cannot be changed later. See . + public enum TaskActionType + { + /// + /// This action performs a command-line operation. For example, the action can run a script, launch an executable, or, if the name + /// of a document is provided, find its associated application and launch the application with the document. + /// + Execute = 0, + + /// This action fires a handler. + ComHandler = 5, + + /// This action sends and e-mail. + SendEmail = 6, + + /// This action shows a message box. + ShowMessage = 7 + } + + /// An interface that exposes the ability to convert an actions functionality to a PowerShell script. + internal interface IBindAsExecAction + { + } + + /// + /// Abstract base class that provides the common properties that are inherited by all action objects. An action object is created by the + /// method. + /// + [PublicAPI] + public abstract class Action : IDisposable, ICloneable, IEquatable, INotifyPropertyChanged, IComparable, IComparable + { + internal IAction iAction; + internal ITask v1Task; + + /// List of unbound values when working with Actions not associated with a registered task. + protected readonly Dictionary unboundValues = new Dictionary(); + + internal Action() + { + } + + internal Action([NotNull] IAction action) => iAction = action; + + internal Action([NotNull] ITask iTask) => v1Task = iTask; + + /// Occurs when a property value changes. + public event PropertyChangedEventHandler PropertyChanged; + + /// Gets the type of the action. + /// The type of the action. + [XmlIgnore] + public TaskActionType ActionType => iAction?.Type ?? InternalActionType; + + /// Gets or sets the identifier of the action. + [DefaultValue(null)] + [XmlAttribute(AttributeName = "id")] + public virtual string Id + { + get => GetProperty(nameof(Id)); + set => SetProperty(nameof(Id), value); + } + + internal abstract TaskActionType InternalActionType { get; } + + /// Creates the specified action. + /// Type of the action to instantiate. + /// of specified type. + public static Action CreateAction(TaskActionType actionType) => Activator.CreateInstance(GetObjectType(actionType)) as Action; + + /// Creates a new object that is a copy of the current instance. + /// A new object that is a copy of this instance. + public object Clone() + { + var ret = CreateAction(ActionType); + ret.CopyProperties(this); + return ret; + } + + /// + /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current + /// instance precedes, follows, or occurs in the same position in the sort order as the other object. + /// + /// An object to compare with this instance. + /// A value that indicates the relative order of the objects being compared. + public int CompareTo(Action obj) => string.Compare(Id, obj?.Id, StringComparison.InvariantCulture); + + /// Releases all resources used by this class. + public virtual void Dispose() + { + if (iAction != null) + Marshal.ReleaseComObject(iAction); + } + + /// Determines whether the specified , is equal to this instance. + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals([CanBeNull] object obj) + { + if (obj is Action) + return Equals((Action)obj); + return base.Equals(obj); + } + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public virtual bool Equals([NotNull] Action other) => ActionType == other.ActionType && Id == other.Id; + + /// Returns a hash code for this instance. + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() => new { A = ActionType, B = Id }.GetHashCode(); + + /// Returns the action Id. + /// String representation of action. + public override string ToString() => Id; + + /// Returns a that represents this action. + /// The culture. + /// String representation of action. + public virtual string ToString([NotNull] System.Globalization.CultureInfo culture) + { + using (new CultureSwitcher(culture)) + return ToString(); + } + + int IComparable.CompareTo(object obj) => CompareTo(obj as Action); + + internal static Action ActionFromScript(string actionType, string script) + { + var tat = TryParse(actionType, TaskActionType.Execute); + var t = GetObjectType(tat); + return (Action)t.InvokeMember("FromPowerShellCommand", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { script }); + } + + internal static Action ConvertFromPowerShellAction(ExecAction execAction) + { + var psi = execAction.ParsePowerShellItems(); + if (psi != null && psi.Length == 2) + { + var a = ActionFromScript(psi[0], psi[1]); + if (a != null) + { + a.v1Task = execAction.v1Task; + a.iAction = execAction.iAction; + return a; + } + } + return null; + } + + /// Creates a specialized class from a defined interface. + /// Version 1.0 interface. + /// Specialized action class + internal static Action CreateAction(ITask iTask) + { + var tempAction = new ExecAction(iTask); + return ConvertFromPowerShellAction(tempAction) ?? tempAction; + } + + /// Creates a specialized class from a defined interface. + /// Version 2.0 Action interface. + /// Specialized action class + internal static Action CreateAction(IAction iAction) + { + var t = GetObjectType(iAction.Type); + return Activator.CreateInstance(t, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { iAction }, null) as Action; + } + + internal static T TryParse(string val, T defaultVal) + { + var ret = defaultVal; + if (val != null) + try { ret = (T)Enum.Parse(typeof(T), val); } catch { } + return ret; + } + + internal virtual void Bind(ITask iTask) + { + if (Id != null) + iTask.SetDataItem("ActionId", Id); + var bindable = this as IBindAsExecAction; + if (bindable != null) + iTask.SetDataItem("ActionType", InternalActionType.ToString()); + unboundValues.TryGetValue("Path", out var o); + iTask.SetApplicationName(bindable != null ? ExecAction.PowerShellPath : o?.ToString() ?? string.Empty); + unboundValues.TryGetValue("Arguments", out o); + iTask.SetParameters(bindable != null ? ExecAction.BuildPowerShellCmd(ActionType.ToString(), GetPowerShellCommand()) : o?.ToString() ?? string.Empty); + unboundValues.TryGetValue("WorkingDirectory", out o); + iTask.SetWorkingDirectory(o?.ToString() ?? string.Empty); + } + + internal virtual void Bind(ITaskDefinition iTaskDef) + { + var iActions = iTaskDef.Actions; + if (iActions.Count >= ActionCollection.MaxActions) + throw new ArgumentOutOfRangeException(nameof(iTaskDef), @"A maximum of 32 actions is allowed within a single task."); + CreateV2Action(iActions); + Marshal.ReleaseComObject(iActions); + foreach (var key in unboundValues.Keys) + { + try { ReflectionHelper.SetProperty(iAction, key, unboundValues[key]); } + catch (TargetInvocationException tie) { throw tie.InnerException; } + catch { } + } + unboundValues.Clear(); + } + + /// Copies the properties from another the current instance. + /// The source . + internal virtual void CopyProperties([NotNull] Action sourceAction) => Id = sourceAction.Id; + + internal abstract void CreateV2Action(IActionCollection iActions); + + internal abstract string GetPowerShellCommand(); + + internal T GetProperty(string propName, T defaultValue = default) + { + if (iAction == null) + return unboundValues.TryGetValue(propName, out var value) ? (T)value : defaultValue; + return ReflectionHelper.GetProperty((TB)iAction, propName, defaultValue); + } + + internal void OnPropertyChanged(string propName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); + + internal void SetProperty(string propName, T value) + { + if (iAction == null) + { + if (Equals(value, default(T))) + unboundValues.Remove(propName); + else + unboundValues[propName] = value; + } + else + ReflectionHelper.SetProperty((TB)iAction, propName, value); + OnPropertyChanged(propName); + } + + [NotNull] + private static Type GetObjectType(TaskActionType actionType) + { + switch (actionType) + { + case TaskActionType.ComHandler: + return typeof(ComHandlerAction); + case TaskActionType.SendEmail: + return typeof(EmailAction); + case TaskActionType.ShowMessage: + return typeof(ShowMessageAction); + + default: + return typeof(ExecAction); + } + } + + /// + /// Represents an action that fires a handler. Only available on Task Scheduler 2.0. Only available for Task Scheduler 2.0 on + /// Windows Vista or Windows Server 2003 and later. + /// + /// + /// This action is the most complex. It allows the task to execute and In-Proc COM server object that implements the ITaskHandler + /// interface. There is a sample project that shows how to do this in the Downloads section. + /// + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("ComHandler", Namespace = TaskDefinition.tns, IsNullable = false)] + public class ComHandlerAction : Action, IBindAsExecAction + { + /// Creates an unbound instance of . + public ComHandlerAction() { } + + /// Creates an unbound instance of . + /// Identifier of the handler class. + /// Addition data associated with the handler. + public ComHandlerAction(Guid classId, [CanBeNull] string data) + { + ClassId = classId; + Data = data; + } + + internal ComHandlerAction([NotNull] ITask task) : base(task) + { + } + + internal ComHandlerAction([NotNull] IAction action) : base(action) + { + } + + /// Gets or sets the identifier of the handler class. + public Guid ClassId + { + get => new Guid(GetProperty(nameof(ClassId), Guid.Empty.ToString())); + set => SetProperty(nameof(ClassId), value.ToString()); + } + + /// Gets the name of the object referred to by . + public string ClassName => GetNameForCLSID(ClassId); + + /// Gets or sets additional data that is associated with the handler. + [DefaultValue(null)] + [CanBeNull] + public string Data + { + get => GetProperty(nameof(Data)); + set => SetProperty(nameof(Data), value); + } + + internal override TaskActionType InternalActionType => TaskActionType.ComHandler; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && ClassId == ((ComHandlerAction)other).ClassId && Data == ((ComHandlerAction)other).Data; + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.ComHandlerAction, ClassId, Data, Id, ClassName); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[Reflection.Assembly\]::LoadFile\('(?:[^']*)'\); \[Microsoft.Win32.TaskScheduler.TaskService\]::RunComHandlerAction\(\[GUID\]\('(?[^']*)'\), '(?[^']*)'\);?\s*$"); + return match.Success ? new ComHandlerAction(new Guid(match.Groups["g"].Value), match.Groups["d"].Value.Replace("''", "'")) : null; + } + + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + ClassId = ((ComHandlerAction)sourceAction).ClassId; + Data = ((ComHandlerAction)sourceAction).Data; + } + } + + internal override void CreateV2Action([NotNull] IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ComHandler); + + internal override string GetPowerShellCommand() + { + var sb = new System.Text.StringBuilder(); + sb.Append($"[Reflection.Assembly]::LoadFile('{Assembly.GetExecutingAssembly().Location}'); "); + sb.Append($"[Microsoft.Win32.TaskScheduler.TaskService]::RunComHandlerAction([GUID]('{ClassId:D}'), '{Data?.Replace("'", "''") ?? string.Empty}'); "); + return sb.ToString(); + } + + /// Gets the name for CLSID. + /// The unique identifier. + /// + [CanBeNull] + private static string GetNameForCLSID(Guid guid) + { + using (var k = Registry.ClassesRoot.OpenSubKey("CLSID", false)) + { + if (k != null) + { + using (var k2 = k.OpenSubKey(guid.ToString("B"), false)) + { + return k2?.GetValue(null) as string; + } + } + } + return null; + } + } + + /// + /// Represents an action that sends an e-mail. Only available for Task Scheduler 2.0 on Windows Vista or Windows Server 2003 and + /// later.This action has been deprecated in Windows 8 and later. However, this library is able to mimic its + /// functionality using PowerShell if the property is set to . To disable this conversion, set the value to . + /// + /// The EmailAction allows for an email to be sent when the task is triggered. + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("SendEmail", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class EmailAction : Action, IBindAsExecAction + { + private const string ImportanceHeader = "Importance"; + + private NamedValueCollection nvc; + private bool validateAttachments = true; + + /// Creates an unbound instance of . + public EmailAction() { } + + /// Creates an unbound instance of . + /// Subject of the e-mail. + /// E-mail address that you want to send the e-mail from. + /// E-mail address or addresses that you want to send the e-mail to. + /// Body of the e-mail that contains the e-mail message. + /// Name of the server that you use to send e-mail from. + public EmailAction([CanBeNull] string subject, [NotNull] string from, [NotNull] string to, [CanBeNull] string body, [NotNull] string mailServer) + { + Subject = subject; + From = from; + To = to; + Body = body; + Server = mailServer; + } + + internal EmailAction([NotNull] ITask task) : base(task) + { + } + + internal EmailAction([NotNull] IAction action) : base(action) + { + } + + /// + /// Gets or sets an array of file paths to be sent as attachments with the e-mail. Each item must be a value + /// containing a path to file. + /// + [XmlArray("Attachments", IsNullable = true)] + [XmlArrayItem("File", typeof(string))] + [DefaultValue(null)] + public object[] Attachments + { + get => GetProperty(nameof(Attachments)); + set + { + if (value != null) + { + if (value.Length > 8) + throw new ArgumentOutOfRangeException(nameof(Attachments), @"Attachments array cannot contain more than 8 items."); + if (validateAttachments) + { + foreach (var o in value) + if (!(o is string) || !System.IO.File.Exists((string)o)) + throw new ArgumentException(@"Each value of the array must contain a valid file reference.", nameof(Attachments)); + } + } + if (iAction == null && (value == null || value.Length == 0)) + { + unboundValues.Remove(nameof(Attachments)); + OnPropertyChanged(nameof(Attachments)); + } + else + SetProperty(nameof(Attachments), value); + } + } + + /// Gets or sets the e-mail address or addresses that you want to Bcc in the e-mail. + [DefaultValue(null)] + public string Bcc + { + get => GetProperty(nameof(Bcc)); + set => SetProperty(nameof(Bcc), value); + } + + /// Gets or sets the body of the e-mail that contains the e-mail message. + [DefaultValue(null)] + public string Body + { + get => GetProperty(nameof(Body)); + set => SetProperty(nameof(Body), value); + } + + /// Gets or sets the e-mail address or addresses that you want to Cc in the e-mail. + [DefaultValue(null)] + public string Cc + { + get => GetProperty(nameof(Cc)); + set => SetProperty(nameof(Cc), value); + } + + /// Gets or sets the e-mail address that you want to send the e-mail from. + [DefaultValue(null)] + public string From + { + get => GetProperty(nameof(From)); + set => SetProperty(nameof(From), value); + } + + /// Gets or sets the header information in the e-mail message to send. + [XmlArray] + [XmlArrayItem("HeaderField", typeof(NameValuePair))] + [NotNull] + public NamedValueCollection HeaderFields + { + get + { + if (nvc == null) + { + nvc = iAction == null ? new NamedValueCollection() : new NamedValueCollection(((IEmailAction)iAction).HeaderFields); + nvc.AttributedXmlFormat = false; + nvc.CollectionChanged += (o, e) => OnPropertyChanged(nameof(HeaderFields)); + } + return nvc; + } + } + + /// Gets or sets the priority of the e-mail message. + /// A that contains the priority of this message. + [XmlIgnore] + [DefaultValue(typeof(System.Net.Mail.MailPriority), "Normal")] + public System.Net.Mail.MailPriority Priority + { + get + { + if (nvc != null && HeaderFields.TryGetValue(ImportanceHeader, out var s)) + return TryParse(s, System.Net.Mail.MailPriority.Normal); + return System.Net.Mail.MailPriority.Normal; + } + set => HeaderFields[ImportanceHeader] = value.ToString(); + } + + /// Gets or sets the e-mail address that you want to reply to. + [DefaultValue(null)] + public string ReplyTo + { + get => GetProperty(nameof(ReplyTo)); + set => SetProperty(nameof(ReplyTo), value); + } + + /// Gets or sets the name of the server that you use to send e-mail from. + [DefaultValue(null)] + public string Server + { + get => GetProperty(nameof(Server)); + set => SetProperty(nameof(Server), value); + } + + /// Gets or sets the subject of the e-mail. + [DefaultValue(null)] + public string Subject + { + get => GetProperty(nameof(Subject)); + set => SetProperty(nameof(Subject), value); + } + + /// Gets or sets the e-mail address or addresses that you want to send the e-mail to. + [DefaultValue(null)] + public string To + { + get => GetProperty(nameof(To)); + set => SetProperty(nameof(To), value); + } + + internal override TaskActionType InternalActionType => TaskActionType.SendEmail; + + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && GetPowerShellCommand() == other.GetPowerShellCommand(); + + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.EmailAction, Subject, To, Cc, Bcc, From, ReplyTo, Body, Server, Id); + + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, @"^Send-MailMessage -From '(?(?:[^']|'')*)' -Subject '(?(?:[^']|'')*)' -SmtpServer '(?(?:[^']|'')*)'(?: -Encoding UTF8)?(?: -To (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Cc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Bcc (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?:(?: -BodyAsHtml)? -Body '(?(?:[^']|'')*)')?(?: -Attachments (?'(?:(?:[^']|'')*)'(?:, '(?:(?:[^']|'')*)')*))?(?: -Priority (?High|Normal|Low))?;?\s*$"); + if (match.Success) + { + var action = new EmailAction(UnPrep(FromUTF8(match.Groups["subject"].Value)), UnPrep(match.Groups["from"].Value), FromPS(match.Groups["to"]), UnPrep(FromUTF8(match.Groups["body"].Value)), UnPrep(match.Groups["server"].Value)) + { Cc = FromPS(match.Groups["cc"]), Bcc = FromPS(match.Groups["bcc"]) }; + action.validateAttachments = false; + if (match.Groups["att"].Success) + action.Attachments = Array.ConvertAll(FromPS(match.Groups["att"].Value), s => s); + action.validateAttachments = true; + if (match.Groups["imp"].Success) + action.HeaderFields[ImportanceHeader] = match.Groups["imp"].Value; + return action; + } + return null; + } + + internal override void Bind(ITaskDefinition iTaskDef) + { + base.Bind(iTaskDef); + nvc?.Bind(((IEmailAction)iAction).HeaderFields); + } + + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + if (((EmailAction)sourceAction).Attachments != null) + Attachments = (object[])((EmailAction)sourceAction).Attachments.Clone(); + Bcc = ((EmailAction)sourceAction).Bcc; + Body = ((EmailAction)sourceAction).Body; + Cc = ((EmailAction)sourceAction).Cc; + From = ((EmailAction)sourceAction).From; + if (((EmailAction)sourceAction).nvc != null) + ((EmailAction)sourceAction).HeaderFields.CopyTo(HeaderFields); + ReplyTo = ((EmailAction)sourceAction).ReplyTo; + Server = ((EmailAction)sourceAction).Server; + Subject = ((EmailAction)sourceAction).Subject; + To = ((EmailAction)sourceAction).To; + } + } + + internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.SendEmail); + + internal override string GetPowerShellCommand() + { + // Send-MailMessage [-To] [-Subject] [[-Body] ] [[-SmtpServer] ] -From + // [-Attachments ] [-Bcc ] [-BodyAsHtml] [-Cc ] [-Credential ] + // [-DeliveryNotificationOption ] [-Encoding ] [-Port ] [-Priority + // ] [-UseSsl] [ ] + var bodyIsHtml = Body != null && Body.Trim().StartsWith("<") && Body.Trim().EndsWith(">"); + var sb = new System.Text.StringBuilder(); + sb.AppendFormat("Send-MailMessage -From '{0}' -Subject '{1}' -SmtpServer '{2}' -Encoding UTF8", Prep(From), ToUTF8(Prep(Subject)), Prep(Server)); + if (!string.IsNullOrEmpty(To)) + sb.AppendFormat(" -To {0}", ToPS(To)); + if (!string.IsNullOrEmpty(Cc)) + sb.AppendFormat(" -Cc {0}", ToPS(Cc)); + if (!string.IsNullOrEmpty(Bcc)) + sb.AppendFormat(" -Bcc {0}", ToPS(Bcc)); + if (bodyIsHtml) + sb.Append(" -BodyAsHtml"); + if (!string.IsNullOrEmpty(Body)) + sb.AppendFormat(" -Body '{0}'", ToUTF8(Prep(Body))); + if (Attachments != null && Attachments.Length > 0) + sb.AppendFormat(" -Attachments {0}", ToPS(Array.ConvertAll(Attachments, o => Prep(o.ToString())))); + var hdr = new List(HeaderFields.Names); + if (hdr.Contains(ImportanceHeader)) + { + var p = Priority; + if (p != System.Net.Mail.MailPriority.Normal) + sb.Append($" -Priority {p}"); + hdr.Remove(ImportanceHeader); + } + if (hdr.Count > 0) + throw new InvalidOperationException("Under Windows 8 and later, EmailAction objects are converted to PowerShell. This action contains headers that are not supported."); + sb.Append("; "); + return sb.ToString(); + + /*var msg = new System.Net.Mail.MailMessage(this.From, this.To, this.Subject, this.Body); if (!string.IsNullOrEmpty(this.Bcc)) msg.Bcc.Add(this.Bcc); if (!string.IsNullOrEmpty(this.Cc)) @@ -669,352 +676,367 @@ namespace winPEAS.TaskScheduler msg.Headers.Add(ha.Name, ha.Value); var client = new System.Net.Mail.SmtpClient(this.Server); client.Send(msg);*/ - } + } - private static string[] FromPS(string p) - { - var list = p.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries); - return Array.ConvertAll(list, i => UnPrep(i).Trim('\'')); - } + private static string[] FromPS(string p) + { + var list = p.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries); + return Array.ConvertAll(list, i => UnPrep(i).Trim('\'')); + } - private static string FromPS(System.Text.RegularExpressions.Group g, string delimeter = ";") => g.Success ? string.Join(delimeter, FromPS(g.Value)) : null; + private static string FromPS(System.Text.RegularExpressions.Group g, string delimeter = ";") => g.Success ? string.Join(delimeter, FromPS(g.Value)) : null; - private static string FromUTF8(string s) - { - var bytes = System.Text.Encoding.UTF8.GetBytes(s); - return System.Text.Encoding.Default.GetString(bytes); - } + private static string FromUTF8(string s) + { + var bytes = System.Text.Encoding.UTF8.GetBytes(s); + return System.Text.Encoding.Default.GetString(bytes); + } - private static string Prep(string s) => s?.Replace("'", "''"); + private static string Prep(string s) => s?.Replace("'", "''"); - private static string ToPS(string input, char[] delimeters = null) - { - if (delimeters == null) - delimeters = new[] { ';', ',' }; - return ToPS(Array.ConvertAll(input.Split(delimeters), i => Prep(i.Trim()))); - } + private static string ToPS(string input, char[] delimeters = null) + { + if (delimeters == null) + delimeters = new[] { ';', ',' }; + return ToPS(Array.ConvertAll(input.Split(delimeters), i => Prep(i.Trim()))); + } - private static string ToPS(string[] input) => string.Join(", ", Array.ConvertAll(input, i => string.Concat("'", i.Trim(), "'"))); + private static string ToPS(string[] input) => string.Join(", ", Array.ConvertAll(input, i => string.Concat("'", i.Trim(), "'"))); - private static string ToUTF8(string s) - { - if (s == null) return null; - var bytes = System.Text.Encoding.Default.GetBytes(s); - return System.Text.Encoding.UTF8.GetString(bytes); - } + private static string ToUTF8(string s) + { + if (s == null) return null; + var bytes = System.Text.Encoding.Default.GetBytes(s); + return System.Text.Encoding.UTF8.GetString(bytes); + } - private static string UnPrep(string s) => s?.Replace("''", "'"); - } + private static string UnPrep(string s) => s?.Replace("''", "'"); + } - /// Represents an action that executes a command-line operation. - /// - /// All versions of the base library support the ExecAction. It only has three properties that allow it to run an executable with parameters. - /// - /// - /// - /// - /// - /// - [XmlRoot("Exec", Namespace = TaskDefinition.tns, IsNullable = false)] - public class ExecAction : Action - { + /// Represents an action that executes a command-line operation. + /// + /// All versions of the base library support the ExecAction. It only has three properties that allow it to run an executable with parameters. + /// + /// + /// + /// + /// + /// + [XmlRoot("Exec", Namespace = TaskDefinition.tns, IsNullable = false)] + public class ExecAction : Action + { #if DEBUG - internal const string PowerShellArgFormat = "-NoExit -Command \"& {{<# {0}:{1} #> {2}}}\""; + internal const string PowerShellArgFormat = "-NoExit -Command \"& {{<# {0}:{1} #> {2}}}\""; #else internal const string PowerShellArgFormat = "-NoLogo -NonInteractive -WindowStyle Hidden -Command \"& {{<# {0}:{1} #> {2}}}\""; #endif - internal const string PowerShellPath = "powershell"; - internal const string ScriptIdentifer = "TSML_20140424"; + internal const string PowerShellPath = "powershell"; + internal const string ScriptIdentifer = "TSML_20140424"; - /// Creates a new instance of an that can be added to . - public ExecAction() { } + /// Creates a new instance of an that can be added to . + public ExecAction() { } - /// Creates a new instance of an that can be added to . - /// Path to an executable file. - /// Arguments associated with the command-line operation. This value can be null. - /// - /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null. - /// - public ExecAction([NotNull] string path, string arguments = null, string workingDirectory = null) - { - Path = path; - Arguments = arguments; - WorkingDirectory = workingDirectory; - } + /// Creates a new instance of an that can be added to . + /// Path to an executable file. + /// Arguments associated with the command-line operation. This value can be null. + /// + /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null. + /// + public ExecAction([NotNull] string path, string arguments = null, string workingDirectory = null) + { + Path = path; + Arguments = arguments; + WorkingDirectory = workingDirectory; + } - internal ExecAction([NotNull] V1Interop.ITask task) : base(task) - { - } + internal ExecAction([NotNull] ITask task) : base(task) + { + } - internal ExecAction([NotNull] IAction action) : base(action) - { - } + internal ExecAction([NotNull] IAction action) : base(action) + { + } - /// Gets or sets the arguments associated with the command-line operation. - [DefaultValue("")] - public string Arguments - { - get - { - if (v1Task != null) - return v1Task.GetParameters(); - return GetProperty(nameof(Arguments), ""); - } - set - { - if (v1Task != null) - v1Task.SetParameters(value); - else - SetProperty(nameof(Arguments), value); - } - } + /// Gets or sets the arguments associated with the command-line operation. + [DefaultValue("")] + public string Arguments + { + get + { + if (v1Task != null) + return v1Task.GetParameters(); + return GetProperty(nameof(Arguments), ""); + } + set + { + if (v1Task != null) + v1Task.SetParameters(value); + else + SetProperty(nameof(Arguments), value); + } + } - /// Gets or sets the path to an executable file. - [XmlElement("Command")] - [DefaultValue("")] - public string Path - { - get - { - if (v1Task != null) - return v1Task.GetApplicationName(); - return GetProperty(nameof(Path), ""); - } - set - { - if (v1Task != null) - v1Task.SetApplicationName(value); - else - SetProperty(nameof(Path), value); - } - } + /// Gets or sets the path to an executable file. + [XmlElement("Command")] + [DefaultValue("")] + public string Path + { + get + { + if (v1Task != null) + return v1Task.GetApplicationName(); + return GetProperty(nameof(Path), ""); + } + set + { + if (v1Task != null) + v1Task.SetApplicationName(value); + else + SetProperty(nameof(Path), value); + } + } - /// - /// Gets or sets the directory that contains either the executable file or the files that are used by the executable file. - /// - [DefaultValue("")] - public string WorkingDirectory - { - get - { - if (v1Task != null) - return v1Task.GetWorkingDirectory(); - return GetProperty(nameof(WorkingDirectory), ""); - } - set - { - if (v1Task != null) - v1Task.SetWorkingDirectory(value); - else - SetProperty(nameof(WorkingDirectory), value); - } - } + /// + /// Gets or sets the directory that contains either the executable file or the files that are used by the executable file. + /// + [DefaultValue("")] + public string WorkingDirectory + { + get + { + if (v1Task != null) + return v1Task.GetWorkingDirectory(); + return GetProperty(nameof(WorkingDirectory), ""); + } + set + { + if (v1Task != null) + v1Task.SetWorkingDirectory(value); + else + SetProperty(nameof(WorkingDirectory), value); + } + } - internal override TaskActionType InternalActionType => TaskActionType.Execute; + internal override TaskActionType InternalActionType => TaskActionType.Execute; - /// Determines whether the specified path is a valid filename and, optionally, if it exists. - /// The path. - /// if set to true check if file exists. - /// if set to true throw exception on error. - /// true if the specified path is a valid filename; otherwise, false. - public static bool IsValidPath(string path, bool checkIfExists = true, bool throwOnException = false) - { - try - { - if (path == null) throw new ArgumentNullException(nameof(path)); - /*if (path.StartsWith("\"") && path.EndsWith("\"") && path.Length > 1) + /// Determines whether the specified path is a valid filename and, optionally, if it exists. + /// The path. + /// if set to true check if file exists. + /// if set to true throw exception on error. + /// true if the specified path is a valid filename; otherwise, false. + public static bool IsValidPath(string path, bool checkIfExists = true, bool throwOnException = false) + { + try + { + if (path == null) throw new ArgumentNullException(nameof(path)); + /*if (path.StartsWith("\"") && path.EndsWith("\"") && path.Length > 1) path = path.Substring(1, path.Length - 2);*/ - var fn = System.IO.Path.GetFileName(path); - System.Diagnostics.Debug.WriteLine($"IsValidPath fn={fn}"); - if (fn == string.Empty) - return false; - var dn = System.IO.Path.GetDirectoryName(path); - System.Diagnostics.Debug.WriteLine($"IsValidPath dir={dn ?? "null"}"); - System.IO.Path.GetFullPath(path); - return true; - } - catch (Exception ex) - { - System.Diagnostics.Debug.WriteLine($"IsValidPath exc={ex}"); - if (throwOnException) throw; - } - return false; - } + var fn = System.IO.Path.GetFileName(path); + System.Diagnostics.Debug.WriteLine($"IsValidPath fn={fn}"); + if (fn == string.Empty) + return false; + var dn = System.IO.Path.GetDirectoryName(path); + System.Diagnostics.Debug.WriteLine($"IsValidPath dir={dn ?? "null"}"); + System.IO.Path.GetFullPath(path); + return true; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"IsValidPath exc={ex}"); + if (throwOnException) throw; + } + return false; + } - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// true if the current object is equal to the parameter; otherwise, false. - public override bool Equals(Action other) => base.Equals(other) && Path == ((ExecAction)other).Path && Arguments == ((ExecAction)other).Arguments && WorkingDirectory == ((ExecAction)other).WorkingDirectory; + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && Path == ((ExecAction)other).Path && Arguments == ((ExecAction)other).Arguments && WorkingDirectory == ((ExecAction)other).WorkingDirectory; - /// - /// Validates the input as a valid filename and optionally checks for its existence. If valid, the property is - /// set to the validated absolute file path. - /// - /// The file path to validate. - /// if set to true check if the file exists. - public void SetValidatedPath([NotNull] string path, bool checkIfExists = true) - { - if (IsValidPath(path, checkIfExists, true)) - Path = path; - } + /// + /// Validates the input as a valid filename and optionally checks for its existence. If valid, the property is + /// set to the validated absolute file path. + /// + /// The file path to validate. + /// if set to true check if the file exists. + public void SetValidatedPath([NotNull] string path, bool checkIfExists = true) + { + if (IsValidPath(path, checkIfExists, true)) + Path = path; + } - /// Gets a string representation of the . - /// String representation of this action. - public override string ToString() => string.Format(Properties.Resources.ExecAction, Path, Arguments, WorkingDirectory, Id); + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => string.Format(Properties.Resources.ExecAction, Path, Arguments, WorkingDirectory, Id); - internal static string BuildPowerShellCmd(string actionType, string cmd) => string.Format(PowerShellArgFormat, ScriptIdentifer, actionType, cmd); + internal static string BuildPowerShellCmd(string actionType, string cmd) => string.Format(PowerShellArgFormat, ScriptIdentifer, actionType, cmd); - internal static ExecAction ConvertToPowerShellAction(Action action) => CreatePowerShellAction(action.ActionType.ToString(), action.GetPowerShellCommand()); + internal static ExecAction ConvertToPowerShellAction(Action action) => CreatePowerShellAction(action.ActionType.ToString(), action.GetPowerShellCommand()); - internal static ExecAction CreatePowerShellAction(string actionType, string cmd) => new ExecAction(PowerShellPath, BuildPowerShellCmd(actionType, cmd)); + internal static ExecAction CreatePowerShellAction(string actionType, string cmd) => new ExecAction(PowerShellPath, BuildPowerShellCmd(actionType, cmd)); - internal static Action FromPowerShellCommand(string p) - { - var match = System.Text.RegularExpressions.Regex.Match(p, "^Start-Process -FilePath '(?

[^']*)'(?: -ArgumentList '(?[^']*)')?(?: -WorkingDirectory '(?[^']*)')?;?\\s*$"); - return match.Success ? new ExecAction(match.Groups["p"].Value, match.Groups["a"].Success ? match.Groups["a"].Value.Replace("''", "'") : null, match.Groups["d"].Success ? match.Groups["d"].Value : null) : null; - } + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, "^Start-Process -FilePath '(?

[^']*)'(?: -ArgumentList '(?[^']*)')?(?: -WorkingDirectory '(?[^']*)')?;?\\s*$"); + return match.Success ? new ExecAction(match.Groups["p"].Value, match.Groups["a"].Success ? match.Groups["a"].Value.Replace("''", "'") : null, match.Groups["d"].Success ? match.Groups["d"].Value : null) : null; + } - ///

Copies the properties from another the current instance. - /// The source . - internal override void CopyProperties(Action sourceAction) - { - if (sourceAction.GetType() == GetType()) - { - base.CopyProperties(sourceAction); - Path = ((ExecAction)sourceAction).Path; - Arguments = ((ExecAction)sourceAction).Arguments; - WorkingDirectory = ((ExecAction)sourceAction).WorkingDirectory; - } - } + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + Path = ((ExecAction)sourceAction).Path; + Arguments = ((ExecAction)sourceAction).Arguments; + WorkingDirectory = ((ExecAction)sourceAction).WorkingDirectory; + } + } - internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.Execute); + internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.Execute); - internal override string GetPowerShellCommand() - { - var sb = new System.Text.StringBuilder($"Start-Process -FilePath '{Path}'"); - if (!string.IsNullOrEmpty(Arguments)) - sb.Append($" -ArgumentList '{Arguments.Replace("'", "''")}'"); - if (!string.IsNullOrEmpty(WorkingDirectory)) - sb.Append($" -WorkingDirectory '{WorkingDirectory}'"); - return sb.Append("; ").ToString(); - } + internal override string GetPowerShellCommand() + { + var sb = new System.Text.StringBuilder($"Start-Process -FilePath '{Path}'"); + if (!string.IsNullOrEmpty(Arguments)) + sb.Append($" -ArgumentList '{Arguments.Replace("'", "''")}'"); + if (!string.IsNullOrEmpty(WorkingDirectory)) + sb.Append($" -WorkingDirectory '{WorkingDirectory}'"); + return sb.Append("; ").ToString(); + } - internal string[] ParsePowerShellItems() - { - if (((Path?.EndsWith(PowerShellPath, StringComparison.InvariantCultureIgnoreCase) ?? false) || - (Path?.EndsWith(PowerShellPath + ".exe", StringComparison.InvariantCultureIgnoreCase) ?? false)) && (Arguments?.Contains(ScriptIdentifer) ?? false)) - { - var match = System.Text.RegularExpressions.Regex.Match(Arguments, @"<# " + ScriptIdentifer + ":(?\\w+) #> (?.+)}\"$"); - if (match.Success) - return new[] { match.Groups["type"].Value, match.Groups["cmd"].Value }; - } - return null; - } - } + internal string[] ParsePowerShellItems() + { + if (((Path?.EndsWith(PowerShellPath, StringComparison.InvariantCultureIgnoreCase) ?? false) || + (Path?.EndsWith(PowerShellPath + ".exe", StringComparison.InvariantCultureIgnoreCase) ?? false)) && (Arguments?.Contains(ScriptIdentifer) ?? false)) + { + var match = System.Text.RegularExpressions.Regex.Match(Arguments, @"<# " + ScriptIdentifer + ":(?\\w+) #> (?.+)}\"$"); + if (match.Success) + return new[] { match.Groups["type"].Value, match.Groups["cmd"].Value }; + } + return null; + } + } - /// - /// Represents an action that shows a message box when a task is activated. Only available for Task Scheduler 2.0 on Windows Vista - /// or Windows Server 2003 and later.This action has been deprecated in Windows 8 and later. However, this - /// library is able to mimic its functionality using PowerShell if the property is - /// set to . To disable this conversion, set the value to . - /// - /// Display a message when the trigger fires using the ShowMessageAction. - /// - /// - /// - /// - /// - [XmlType(IncludeInSchema = true)] - [XmlRoot("ShowMessage", Namespace = TaskDefinition.tns, IsNullable = false)] - public sealed class ShowMessageAction : Action, IBindAsExecAction - { - /// Creates a new unbound instance of . - public ShowMessageAction() { } + /// + /// Represents an action that shows a message box when a task is activated. Only available for Task Scheduler 2.0 on Windows Vista + /// or Windows Server 2003 and later.This action has been deprecated in Windows 8 and later. However, this + /// library is able to mimic its functionality using PowerShell if the property is + /// set to . To disable this conversion, set the value to . + /// + /// Display a message when the trigger fires using the ShowMessageAction. + /// + /// + /// + /// + /// + [XmlType(IncludeInSchema = true)] + [XmlRoot("ShowMessage", Namespace = TaskDefinition.tns, IsNullable = false)] + public sealed class ShowMessageAction : Action, IBindAsExecAction + { + /// Creates a new unbound instance of . + public ShowMessageAction() + { + } - /// Creates a new unbound instance of . - /// Message text that is displayed in the body of the message box. - /// Title of the message box. - public ShowMessageAction([CanBeNull] string messageBody, [CanBeNull] string title) - { - MessageBody = messageBody; - Title = title; - } + /// Creates a new unbound instance of . + /// Message text that is displayed in the body of the message box. + /// Title of the message box. + public ShowMessageAction([CanBeNull] string messageBody, [CanBeNull] string title) + { + MessageBody = messageBody; + Title = title; + } - internal ShowMessageAction([NotNull] V1Interop.ITask task) : base(task) - { - } + internal ShowMessageAction([NotNull] ITask task) : base(task) + { + } - internal ShowMessageAction([NotNull] IAction action) : base(action) - { - } + internal ShowMessageAction([NotNull] IAction action) : base(action) + { + } - /// Gets or sets the message text that is displayed in the body of the message box. - [XmlElement("Body")] - [DefaultValue(null)] - public string MessageBody - { - get => GetProperty(nameof(MessageBody)); - set => SetProperty(nameof(MessageBody), value); - } + /// Gets or sets the message text that is displayed in the body of the message box. + [XmlElement("Body")] + [DefaultValue(null)] + public string MessageBody + { + get => GetProperty(nameof(MessageBody)); + set => SetProperty(nameof(MessageBody), value); + } - /// Gets or sets the title of the message box. - [DefaultValue(null)] - public string Title - { - get => GetProperty(nameof(Title)); - set => SetProperty(nameof(Title), value); - } + /// Gets or sets the title of the message box. + [DefaultValue(null)] + public string Title + { + get => GetProperty(nameof(Title)); + set => SetProperty(nameof(Title), value); + } - internal override TaskActionType InternalActionType => TaskActionType.ShowMessage; + internal override TaskActionType InternalActionType => TaskActionType.ShowMessage; - /// Indicates whether the current object is equal to another object of the same type. - /// An object to compare with this object. - /// true if the current object is equal to the parameter; otherwise, false. - public override bool Equals(Action other) => base.Equals(other) && string.Equals(Title, (other as ShowMessageAction)?.Title) && string.Equals(MessageBody, (other as ShowMessageAction)?.MessageBody); + /// Indicates whether the current object is equal to another object of the same type. + /// An object to compare with this object. + /// true if the current object is equal to the parameter; otherwise, false. + public override bool Equals(Action other) => base.Equals(other) && + string.Equals(Title, (other as ShowMessageAction)?.Title) && + string.Equals(MessageBody, + (other as ShowMessageAction)?.MessageBody); - /// Gets a string representation of the . - /// String representation of this action. - public override string ToString() => string.Format(Properties.Resources.ShowMessageAction, Title, MessageBody, Id); + /// Gets a string representation of the . + /// String representation of this action. + public override string ToString() => + string.Format(Properties.Resources.ShowMessageAction, Title, MessageBody, Id); - internal static Action FromPowerShellCommand(string p) - { - var match = System.Text.RegularExpressions.Regex.Match(p, @"^\[System.Reflection.Assembly\]::LoadWithPartialName\('System.Windows.Forms'\); \[System.Windows.Forms.MessageBox\]::Show\('(?(?:[^']|'')*)'(?:,'(?(?:[^']|'')*)')?\);?\s*$"); - return match.Success ? new ShowMessageAction(match.Groups["msg"].Value.Replace("''", "'"), match.Groups["t"].Success ? match.Groups["t"].Value.Replace("''", "'") : null) : null; - } + internal static Action FromPowerShellCommand(string p) + { + var match = System.Text.RegularExpressions.Regex.Match(p, + @"^\[System.Reflection.Assembly\]::LoadWithPartialName\('System.Windows.Forms'\); \[System.Windows.Forms.MessageBox\]::Show\('(?(?:[^']|'')*)'(?:,'(?(?:[^']|'')*)')?\);?\s*$"); + return match.Success + ? new ShowMessageAction(match.Groups["msg"].Value.Replace("''", "'"), + match.Groups["t"].Success ? match.Groups["t"].Value.Replace("''", "'") : null) + : null; + } - /// Copies the properties from another the current instance. - /// The source . - internal override void CopyProperties(Action sourceAction) - { - if (sourceAction.GetType() == GetType()) - { - base.CopyProperties(sourceAction); - Title = ((ShowMessageAction)sourceAction).Title; - MessageBody = ((ShowMessageAction)sourceAction).MessageBody; - } - } + /// Copies the properties from another the current instance. + /// The source . + internal override void CopyProperties(Action sourceAction) + { + if (sourceAction.GetType() == GetType()) + { + base.CopyProperties(sourceAction); + Title = ((ShowMessageAction) sourceAction).Title; + MessageBody = ((ShowMessageAction) sourceAction).MessageBody; + } + } - internal override void CreateV2Action(IActionCollection iActions) => iAction = iActions.Create(TaskActionType.ShowMessage); + internal override void CreateV2Action(IActionCollection iActions) => + iAction = iActions.Create(TaskActionType.ShowMessage); - internal override string GetPowerShellCommand() - { - // [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Your_Desired_Message','Your_Desired_Title'); - var sb = new System.Text.StringBuilder("[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('"); - sb.Append(MessageBody.Replace("'", "''")); - if (Title != null) - { - sb.Append("','"); - sb.Append(Title.Replace("'", "''")); - } - sb.Append("'); "); - return sb.ToString(); - } - } -} + internal override string GetPowerShellCommand() + { + // [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Your_Desired_Message','Your_Desired_Title'); + var sb = new System.Text.StringBuilder( + "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('"); + sb.Append(MessageBody.Replace("'", "''")); + if (Title != null) + { + sb.Append("','"); + sb.Append(Title.Replace("'", "''")); + } + + sb.Append("'); "); + return sb.ToString(); + } + } + + } +} \ No newline at end of file diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/ActionCollection.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/ActionCollection.cs index 78f73a9..8e8032f 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/ActionCollection.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/ActionCollection.cs @@ -10,6 +10,8 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using winPEAS.TaskScheduler.TaskEditor.Native; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { @@ -25,13 +27,13 @@ namespace winPEAS.TaskScheduler /// /// Convert actions under Version 1 of the library (Windows XP or Windows Server 2003 and earlier). This option supports multiple - /// actions of all types. If not specified, only a single is supported. Developer must ensure that + /// actions of all types. If not specified, only a single is supported. Developer must ensure that /// PowerShell v2 or higher is installed on the target computer. /// Version1 = 1, /// - /// Convert all and references to their PowerShell equivalents on systems + /// Convert all and references to their PowerShell equivalents on systems /// on or after Windows 8 / Server 2012. /// Version2 = 2, @@ -51,18 +53,18 @@ namespace winPEAS.TaskScheduler private bool inV2set; private PowerShellActionPlatformOption psConvert = PowerShellActionPlatformOption.Version2; private readonly List v1Actions; - private V1Interop.ITask v1Task; - private readonly V2Interop.IActionCollection v2Coll; - private V2Interop.ITaskDefinition v2Def; + private ITask v1Task; + private readonly IActionCollection v2Coll; + private ITaskDefinition v2Def; - internal ActionCollection([NotNull] V1Interop.ITask task) + internal ActionCollection([NotNull] ITask task) { v1Task = task; v1Actions = GetV1Actions(); PowerShellConversion = Action.TryParse(v1Task.GetDataItem(nameof(PowerShellConversion)), psConvert | PowerShellActionPlatformOption.Version2); } - internal ActionCollection([NotNull] V2Interop.ITaskDefinition iTaskDef) + internal ActionCollection([NotNull] ITaskDefinition iTaskDef) { v2Def = iTaskDef; v2Coll = iTaskDef.Actions; @@ -108,7 +110,7 @@ namespace winPEAS.TaskScheduler } /// - /// Gets or sets the systems under which unsupported actions will be converted to PowerShell instances. + /// Gets or sets the systems under which unsupported actions will be converted to PowerShell instances. /// /// The PowerShell platform options. /// @@ -120,12 +122,12 @@ namespace winPEAS.TaskScheduler /// /// If set to , then actions will be converted only under Version 1 of the /// library (Windows XP or Windows Server 2003 and earlier). This option supports multiple actions of all types. If not specified, - /// only a single is supported. Developer must ensure that PowerShell v2 or higher is installed on the + /// only a single is supported. Developer must ensure that PowerShell v2 or higher is installed on the /// target computer. /// /// /// If set to (which is the default value), then and references will be converted to their PowerShell equivalents on systems + /// cref="Action.ShowMessageAction"/> and references will be converted to their PowerShell equivalents on systems /// on or after Windows 8 / Server 2012. /// /// @@ -291,8 +293,8 @@ namespace winPEAS.TaskScheduler action.Bind(v2Def); else { - if (!SupportV1Conversion && (v1Actions.Count >= 1 || !(action is ExecAction))) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + if (!SupportV1Conversion && (v1Actions.Count >= 1 || !(action is Action.ExecAction))) + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); v1Actions.Add(action); SaveV1Actions(); } @@ -302,16 +304,16 @@ namespace winPEAS.TaskScheduler return action; } - /// Adds an to the task. + /// Adds an to the task. /// Path to an executable file. /// Arguments associated with the command-line operation. This value can be null. /// /// Directory that contains either the executable file or the files that are used by the executable file. This value can be null. /// - /// The bound that was added to the collection. + /// The bound that was added to the collection. [NotNull] - public ExecAction Add([NotNull] string path, [CanBeNull] string arguments = null, [CanBeNull] string workingDirectory = null) => - Add(new ExecAction(path, arguments, workingDirectory)); + public Action.ExecAction Add([NotNull] string path, [CanBeNull] string arguments = null, [CanBeNull] string workingDirectory = null) => + Add(new Action.ExecAction(path, arguments, workingDirectory)); /// Adds a new instance to the task. /// Type of task to be created @@ -324,7 +326,7 @@ namespace winPEAS.TaskScheduler if (v1Task != null) { if (!SupportV1Conversion && (v1Actions.Count >= 1 || actionType != TaskActionType.Execute)) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); return Action.CreateAction(v1Task); } return Action.CreateAction(v2Coll.Create(actionType)); @@ -345,7 +347,7 @@ namespace winPEAS.TaskScheduler var list = new List(actions); var at = list.Count == 1 && list[0].ActionType == TaskActionType.Execute; if (!SupportV1Conversion && ((v1Actions.Count + list.Count) > 1 || !at)) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); v1Actions.AddRange(actions); SaveV1Actions(); } @@ -492,7 +494,7 @@ namespace winPEAS.TaskScheduler public IEnumerator GetEnumerator() { if (v2Coll != null) - return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], Action.CreateAction); + return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], Action.CreateAction); return v1Actions.GetEnumerator(); } @@ -537,8 +539,8 @@ namespace winPEAS.TaskScheduler } else { - if (!SupportV1Conversion && (index > 0 || !(action is ExecAction))) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + if (!SupportV1Conversion && (index > 0 || !(action is Action.ExecAction))) + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); v1Actions.Insert(index, action); SaveV1Actions(); } @@ -673,8 +675,8 @@ namespace winPEAS.TaskScheduler { var action = this[i]; var bindable = action as IBindAsExecAction; - if (bindable != null && !(action is ComHandlerAction)) - this[i] = ExecAction.ConvertToPowerShellAction(action); + if (bindable != null && !(action is Action.ComHandlerAction)) + this[i] = Action.ExecAction.ConvertToPowerShellAction(action); } } } @@ -684,7 +686,7 @@ namespace winPEAS.TaskScheduler var ret = new List(); if (v1Task != null && v1Task.GetDataItem("ActionType") != "EMPTY") { - var exec = new ExecAction(v1Task); + var exec = new Action.ExecAction(v1Task); var items = exec.ParsePowerShellItems(); if (items != null) { @@ -704,7 +706,7 @@ namespace winPEAS.TaskScheduler } } else - ret.Add(ExecAction.ConvertFromPowerShellAction(exec)); + ret.Add(Action.ExecAction.ConvertFromPowerShellAction(exec)); } else if (!string.IsNullOrEmpty(exec.Path)) { @@ -733,21 +735,21 @@ namespace winPEAS.TaskScheduler else if (v1Actions.Count == 1) { if (!SupportV1Conversion && v1Actions[0].ActionType != TaskActionType.Execute) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); v1Task.SetDataItem("ActionType", null); v1Actions[0].Bind(v1Task); } else { if (!SupportV1Conversion) - throw new NotV1SupportedException($"Only a single {nameof(ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); + throw new NotV1SupportedException($"Only a single {nameof(Action.ExecAction)} is supported unless the {nameof(PowerShellConversion)} property includes the {nameof(PowerShellActionPlatformOption.Version1)} value."); // Build list of internal PowerShell scripts var sb = new System.Text.StringBuilder(); foreach (var item in v1Actions) sb.Append($"<# {item.Id ?? "NO_ID"}:{item.ActionType} #> {item.GetPowerShellCommand()} "); // Build and save PS ExecAction - var ea = ExecAction.CreatePowerShellAction("MULTIPLE", sb.ToString()); + var ea = Action.ExecAction.CreatePowerShellAction("MULTIPLE", sb.ToString()); ea.Bind(v1Task); v1Task.SetDataItem("ActionId", null); v1Task.SetDataItem("ActionType", "MULTIPLE"); @@ -760,7 +762,7 @@ namespace winPEAS.TaskScheduler { for (var i = 0; i < Count; i++) { - var action = this[i] as ExecAction; + var action = this[i] as Action.ExecAction; if (action != null) { var newAction = Action.ConvertFromPowerShellAction(action); diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/NamedValueCollection.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/NamedValueCollection.cs index d64d87e..d518061 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/NamedValueCollection.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/NamedValueCollection.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using winPEAS.TaskScheduler.TaskEditor.Native; -using winPEAS.TaskScheduler.V2Interop; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Task.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Task.cs index 089866e..c69b47e 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Task.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Task.cs @@ -20,9 +20,10 @@ using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; using winPEAS.TaskScheduler.TaskEditor.Native; -using winPEAS.TaskScheduler.V1Interop; -using winPEAS.TaskScheduler.V2Interop; -using TaskStatus = winPEAS.TaskScheduler.V1Interop.TaskStatus; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; +using IPrincipal = winPEAS.TaskScheduler.V2.IPrincipal; +using TaskStatus = winPEAS.TaskScheduler.V1.TaskStatus; namespace winPEAS.TaskScheduler { @@ -1125,7 +1126,7 @@ namespace winPEAS.TaskScheduler } /// Gets the results that were returned the last time the registered task was run. - /// The value returned is the last exit code of the last program run via an . + /// The value returned is the last exit code of the last program run via an . /// /// /// /// Gets a value indicating whether this task is read only. Only available if is true. + /// cref="TaskScheduler.TaskService.AllowReadOnlyTasks"/> is true. /// /// true if read only; otherwise, false. public bool ReadOnly { get; internal set; } @@ -1862,10 +1863,10 @@ namespace winPEAS.TaskScheduler public event PropertyChangedEventHandler PropertyChanged; /// Gets a collection of actions that are performed by the task. - [XmlArrayItem(ElementName = "Exec", IsNullable = true, Type = typeof(ExecAction))] - [XmlArrayItem(ElementName = "ShowMessage", IsNullable = true, Type = typeof(ShowMessageAction))] - [XmlArrayItem(ElementName = "ComHandler", IsNullable = true, Type = typeof(ComHandlerAction))] - [XmlArrayItem(ElementName = "SendEmail", IsNullable = true, Type = typeof(EmailAction))] + [XmlArrayItem(ElementName = "Exec", IsNullable = true, Type = typeof(Action.ExecAction))] + [XmlArrayItem(ElementName = "ShowMessage", IsNullable = true, Type = typeof(Action.ShowMessageAction))] + [XmlArrayItem(ElementName = "ComHandler", IsNullable = true, Type = typeof(Action.ComHandlerAction))] + [XmlArrayItem(ElementName = "SendEmail", IsNullable = true, Type = typeof(Action.EmailAction))] [XmlArray] [NotNull, ItemNotNull] public ActionCollection Actions => actions ??= v2Def != null ? new ActionCollection(v2Def) : new ActionCollection(v1Task); @@ -2006,13 +2007,13 @@ namespace winPEAS.TaskScheduler var a = Actions[i]; switch (a) { - case EmailAction _: + case Action.EmailAction _: bad = true; if (!throwExceptionWithDetails) return false; TryAdd(ex.Data, $"Actions[{i}]", "== typeof(EmailAction)"); break; - case ShowMessageAction _: + case Action.ShowMessageAction _: bad = true; if (!throwExceptionWithDetails) return false; TryAdd(ex.Data, $"Actions[{i}]", "== typeof(ShowMessageAction)"); @@ -2271,9 +2272,9 @@ namespace winPEAS.TaskScheduler if (Settings.StartWhenAvailable) { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Settings.StartWhenAvailable", "must be false.")); } - if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version1) != PowerShellActionPlatformOption.Version1 && (Actions.ContainsType(typeof(EmailAction)) || Actions.ContainsType(typeof(ShowMessageAction)) || Actions.ContainsType(typeof(ComHandlerAction)))) + if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version1) != PowerShellActionPlatformOption.Version1 && (Actions.ContainsType(typeof(Action.EmailAction)) || Actions.ContainsType(typeof(Action.ShowMessageAction)) || Actions.ContainsType(typeof(Action.ComHandlerAction)))) { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2, "Actions", "may only contain ExecAction types unless Actions.PowerShellConversion includes Version1.")); } - if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version2) != PowerShellActionPlatformOption.Version2 && (Actions.ContainsType(typeof(EmailAction)) || Actions.ContainsType(typeof(ShowMessageAction)))) + if ((Actions.PowerShellConversion & PowerShellActionPlatformOption.Version2) != PowerShellActionPlatformOption.Version2 && (Actions.ContainsType(typeof(Action.EmailAction)) || Actions.ContainsType(typeof(Action.ShowMessageAction)))) { list.Add(new TaskCompatibilityEntry(TaskCompatibility.V2_1, "Actions", "may only contain ExecAction and ComHanlderAction types unless Actions.PowerShellConversion includes Version2.")); } try @@ -2332,14 +2333,14 @@ namespace winPEAS.TaskScheduler public sealed class TaskPrincipal : IDisposable, IXmlSerializable, INotifyPropertyChanged { private const string localSystemAcct = "SYSTEM"; - private readonly V2Interop.IPrincipal v2Principal; + private readonly IPrincipal v2Principal; private readonly IPrincipal2 v2Principal2; private readonly Func xmlFunc; private TaskPrincipalPrivileges reqPriv; private string v1CachedAcctInfo; private ITask v1Task; - internal TaskPrincipal([NotNull] V2Interop.IPrincipal iPrincipal, Func defXml) + internal TaskPrincipal([NotNull] IPrincipal iPrincipal, Func defXml) { xmlFunc = defXml; v2Principal = iPrincipal; diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskCollection.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskCollection.cs index 38ea994..c6f4bc0 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskCollection.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskCollection.cs @@ -4,6 +4,8 @@ using System.Runtime.InteropServices; using System.Text.RegularExpressions; using winPEAS.TaskScheduler.TaskEditor.Native; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { @@ -14,11 +16,11 @@ namespace winPEAS.TaskScheduler public sealed class RunningTaskCollection : IReadOnlyList, IDisposable { private readonly TaskService svc; - private readonly V2Interop.IRunningTaskCollection v2Coll; + private readonly IRunningTaskCollection v2Coll; internal RunningTaskCollection([NotNull] TaskService svc) => this.svc = svc; - internal RunningTaskCollection([NotNull] TaskService svc, [NotNull] V2Interop.IRunningTaskCollection iTaskColl) + internal RunningTaskCollection([NotNull] TaskService svc, [NotNull] IRunningTaskCollection iTaskColl) { this.svc = svc; v2Coll = iTaskColl; @@ -73,9 +75,9 @@ namespace winPEAS.TaskScheduler public IEnumerator GetEnumerator() { if (v2Coll != null) - return new ComEnumerator(() => v2Coll.Count, (object o) => v2Coll[o], o => + return new ComEnumerator(() => v2Coll.Count, (object o) => v2Coll[o], o => { - V2Interop.IRegisteredTask task = null; + IRegisteredTask task = null; try { task = TaskService.GetTask(svc.v2TaskService, o.Path); } catch { } return task == null ? null : new RunningTask(svc, task, o); }); @@ -151,9 +153,9 @@ namespace winPEAS.TaskScheduler { private readonly TaskFolder fld; private readonly TaskService svc; - private readonly V2Interop.IRegisteredTaskCollection v2Coll; + private readonly IRegisteredTaskCollection v2Coll; private Regex filter; - private V1Interop.ITaskScheduler v1TS; + private ITaskScheduler v1TS; internal TaskCollection([NotNull] TaskService svc, Regex filter = null) { @@ -162,7 +164,7 @@ namespace winPEAS.TaskScheduler v1TS = svc.v1TaskScheduler; } - internal TaskCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.IRegisteredTaskCollection iTaskColl, Regex filter = null) + internal TaskCollection([NotNull] TaskFolder folder, [NotNull] IRegisteredTaskCollection iTaskColl, Regex filter = null) { svc = folder.TaskService; Filter = filter; @@ -288,9 +290,9 @@ namespace winPEAS.TaskScheduler { private readonly Regex filter; private readonly TaskService svc; - private readonly V1Interop.IEnumWorkItems wienum; + private readonly IEnumWorkItems wienum; private string curItem; - private V1Interop.ITaskScheduler ts; + private ITaskScheduler ts; /// Internal constructor /// TaskService instance @@ -322,7 +324,7 @@ namespace winPEAS.TaskScheduler } } - internal V1Interop.ITask ICurrent => TaskService.GetTask(ts, curItem); + internal ITask ICurrent => TaskService.GetTask(ts, curItem); /// Releases all resources used by this class. public void Dispose() @@ -346,7 +348,7 @@ namespace winPEAS.TaskScheduler wienum?.Next(1, out names, out uFetched); if (uFetched != 1) break; - using (var name = new V1Interop.CoTaskMemString(Marshal.ReadIntPtr(names))) + using (var name = new CoTaskMemString(Marshal.ReadIntPtr(names))) curItem = name.ToString(); if (curItem != null && curItem.EndsWith(".job", StringComparison.InvariantCultureIgnoreCase)) curItem = curItem.Remove(curItem.Length - 4); @@ -361,7 +363,7 @@ namespace winPEAS.TaskScheduler continue; } - V1Interop.ITask itask = null; + ITask itask = null; try { itask = ICurrent; valid = true; } catch { valid = false; } finally { Marshal.ReleaseComObject(itask); } @@ -378,11 +380,11 @@ namespace winPEAS.TaskScheduler } } - private class V2TaskEnumerator : ComEnumerator + private class V2TaskEnumerator : ComEnumerator { private readonly Regex filter; - internal V2TaskEnumerator(TaskFolder folder, V2Interop.IRegisteredTaskCollection iTaskColl, Regex filter = null) : + internal V2TaskEnumerator(TaskFolder folder, IRegisteredTaskCollection iTaskColl, Regex filter = null) : base(() => iTaskColl.Count, (object o) => iTaskColl[o], o => Task.CreateTask(folder.TaskService, o)) => this.filter = filter; public override bool MoveNext() diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolder.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolder.cs index d64609d..2bc7803 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolder.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolder.cs @@ -8,8 +8,8 @@ using System.Security.AccessControl; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using winPEAS.TaskScheduler.V1Interop; -using winPEAS.TaskScheduler.V2Interop; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolderCollection.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolderCollection.cs index 03c7b19..469aa69 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolderCollection.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskFolderCollection.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using winPEAS.TaskScheduler.TaskEditor.Native; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { @@ -16,11 +17,11 @@ namespace winPEAS.TaskScheduler private const string IndexerName = "Item[]"; private readonly TaskFolder parent; private readonly TaskFolder[] v1FolderList; - private readonly V2Interop.ITaskFolderCollection v2FolderList; + private readonly ITaskFolderCollection v2FolderList; internal TaskFolderCollection() => v1FolderList = new TaskFolder[0]; - internal TaskFolderCollection([NotNull] TaskFolder folder, [NotNull] V2Interop.ITaskFolderCollection iCollection) + internal TaskFolderCollection([NotNull] TaskFolder folder, [NotNull] ITaskFolderCollection iCollection) { parent = folder; v2FolderList = iCollection; @@ -163,7 +164,7 @@ namespace winPEAS.TaskScheduler public IEnumerator GetEnumerator() { if (v2FolderList != null) - return new ComEnumerator(() => v2FolderList.Count, (object o) => v2FolderList[o], o => new TaskFolder(parent.TaskService, o)); + return new ComEnumerator(() => v2FolderList.Count, (object o) => v2FolderList[o], o => new TaskFolder(parent.TaskService, o)); return Array.AsReadOnly(v1FolderList).GetEnumerator(); } diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskService.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskService.cs index 175f00e..d39962c 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskService.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TaskService.cs @@ -6,12 +6,14 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { /// /// Quick simple trigger types for the - /// method. + /// method. /// public enum QuickTriggerType { @@ -78,14 +80,14 @@ namespace winPEAS.TaskScheduler { internal static readonly bool LibraryIsV2 = Environment.OSVersion.Version.Major >= 6; internal static readonly Guid PowerShellActionGuid = new Guid("dab4c1e3-cd12-46f1-96fc-3981143c9bab"); - private static Guid CLSID_Ctask = typeof(V1Interop.CTask).GUID; - private static Guid IID_ITask = typeof(V1Interop.ITask).GUID; + private static Guid CLSID_Ctask = typeof(CTask).GUID; + private static Guid IID_ITask = typeof(ITask).GUID; [ThreadStatic] private static TaskService instance; private static Version osLibVer; - internal V1Interop.ITaskScheduler v1TaskScheduler; - internal V2Interop.ITaskService v2TaskService; + internal ITaskScheduler v1TaskScheduler; + internal ITaskService v2TaskService; private bool connecting; private bool forceV1; private bool initializing; @@ -586,7 +588,7 @@ namespace winPEAS.TaskScheduler throw new ArgumentOutOfRangeException(nameof(trigger), trigger, null); } - return AddTask(path, newTrigger, new ExecAction(exePath, arguments), userId, password, logonType, description); + return AddTask(path, newTrigger, new Action.ExecAction(exePath, arguments), userId, password, logonType, description); } /// Signals the object that initialization is starting. @@ -765,9 +767,9 @@ namespace winPEAS.TaskScheduler info.AddValue("forceV1", forceV1, typeof(bool)); } - internal static V2Interop.IRegisteredTask GetTask([NotNull] V2Interop.ITaskService iSvc, [NotNull] string name) + internal static IRegisteredTask GetTask([NotNull] ITaskService iSvc, [NotNull] string name) { - V2Interop.ITaskFolder fld = null; + ITaskFolder fld = null; try { fld = iSvc.GetFolder("\\"); @@ -783,7 +785,7 @@ namespace winPEAS.TaskScheduler } } - internal static V1Interop.ITask GetTask([NotNull] V1Interop.ITaskScheduler iSvc, [NotNull] string name) + internal static ITask GetTask([NotNull] ITaskScheduler iSvc, [NotNull] string name) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); @@ -891,7 +893,7 @@ namespace winPEAS.TaskScheduler if (LibraryIsV2 && !forceV1) { - v2TaskService = new V2Interop.ITaskService(); + v2TaskService = new ITaskService(); if (!string.IsNullOrEmpty(targetServer)) { // Check to ensure character only server name. (Suggested by bigsan) @@ -912,7 +914,7 @@ namespace winPEAS.TaskScheduler else { v1Impersonation = new WindowsImpersonatedIdentity(userName, userDomain, userPassword); - v1TaskScheduler = new V1Interop.ITaskScheduler(); + v1TaskScheduler = new ITaskScheduler(); if (!string.IsNullOrEmpty(targetServer)) { // Check to ensure UNC format for server name. (Suggested by bigsan) diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Trigger.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Trigger.cs index e3e3dd1..50753c6 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/Trigger.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/Trigger.cs @@ -9,7 +9,8 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using winPEAS.Properties; -using winPEAS.TaskScheduler.V2Interop; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { @@ -187,7 +188,7 @@ namespace winPEAS.TaskScheduler /// Creates an unbound instance of a . public BootTrigger() : base(TaskTriggerType.Boot) { } - internal BootTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnSystemStart) + internal BootTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.OnSystemStart) { } @@ -327,7 +328,7 @@ namespace winPEAS.TaskScheduler /// Interval between the days in the schedule. public DailyTrigger(short daysInterval = 1) : base(TaskTriggerType.Daily) => DaysInterval = daysInterval; - internal DailyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunDaily) + internal DailyTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.RunDaily) { if (v1TriggerData.Data.daily.DaysInterval == 0) v1TriggerData.Data.daily.DaysInterval = 1; @@ -663,7 +664,7 @@ namespace winPEAS.TaskScheduler /// Creates an unbound instance of a . public IdleTrigger() : base(TaskTriggerType.Idle) { } - internal IdleTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnIdle) + internal IdleTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.OnIdle) { } @@ -700,7 +701,7 @@ namespace winPEAS.TaskScheduler /// Creates an unbound instance of a . public LogonTrigger() : base(TaskTriggerType.Logon) { } - internal LogonTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.OnLogon) + internal LogonTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.OnLogon) { } @@ -783,7 +784,7 @@ namespace winPEAS.TaskScheduler WeeksOfMonth = weeksOfMonth; } - internal MonthlyDOWTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunMonthlyDOW) + internal MonthlyDOWTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.RunMonthlyDOW) { if (v1TriggerData.Data.monthlyDOW.Months == 0) v1TriggerData.Data.monthlyDOW.Months = MonthsOfTheYear.AllMonths; @@ -1112,7 +1113,7 @@ namespace winPEAS.TaskScheduler MonthsOfYear = monthsOfYear; } - internal MonthlyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunMonthly) + internal MonthlyTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.RunMonthly) { if (v1TriggerData.Data.monthlyDate.Months == 0) v1TriggerData.Data.monthlyDate.Months = MonthsOfTheYear.AllMonths; @@ -1563,7 +1564,7 @@ namespace winPEAS.TaskScheduler if (v2Pattern != null) return v2Pattern.StopAtDurationEnd; if (pTrigger != null) - return (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd; + return (pTrigger.v1TriggerData.Flags & TaskTriggerFlags.KillAtDurationEnd) == TaskTriggerFlags.KillAtDurationEnd; return unboundStopAtDurationEnd; } set @@ -1573,9 +1574,9 @@ namespace winPEAS.TaskScheduler else if (pTrigger != null) { if (value) - pTrigger.v1TriggerData.Flags |= V1Interop.TaskTriggerFlags.KillAtDurationEnd; + pTrigger.v1TriggerData.Flags |= TaskTriggerFlags.KillAtDurationEnd; else - pTrigger.v1TriggerData.Flags &= ~V1Interop.TaskTriggerFlags.KillAtDurationEnd; + pTrigger.v1TriggerData.Flags &= ~TaskTriggerFlags.KillAtDurationEnd; Bind(); } else @@ -1612,7 +1613,7 @@ namespace winPEAS.TaskScheduler if (v2Pattern != null) return v2Pattern.StopAtDurationEnd || !string.IsNullOrEmpty(v2Pattern.Duration) || !string.IsNullOrEmpty(v2Pattern.Interval); if (pTrigger != null) - return (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd || pTrigger.v1TriggerData.MinutesDuration > 0 || pTrigger.v1TriggerData.MinutesInterval > 0; + return (pTrigger.v1TriggerData.Flags & TaskTriggerFlags.KillAtDurationEnd) == TaskTriggerFlags.KillAtDurationEnd || pTrigger.v1TriggerData.MinutesDuration > 0 || pTrigger.v1TriggerData.MinutesInterval > 0; return false; } @@ -1642,7 +1643,7 @@ namespace winPEAS.TaskScheduler v2Pattern.Interval = $"PT{pTrigger.v1TriggerData.MinutesInterval}M"; if (pTrigger.v1TriggerData.MinutesDuration != 0) v2Pattern.Duration = $"PT{pTrigger.v1TriggerData.MinutesDuration}M"; - v2Pattern.StopAtDurationEnd = (pTrigger.v1TriggerData.Flags & V1Interop.TaskTriggerFlags.KillAtDurationEnd) == V1Interop.TaskTriggerFlags.KillAtDurationEnd; + v2Pattern.StopAtDurationEnd = (pTrigger.v1TriggerData.Flags & TaskTriggerFlags.KillAtDurationEnd) == TaskTriggerFlags.KillAtDurationEnd; } } @@ -1801,7 +1802,7 @@ namespace winPEAS.TaskScheduler /// Date and time for the trigger to fire. public TimeTrigger(DateTime startBoundary) : base(TaskTriggerType.Time) => StartBoundary = startBoundary; - internal TimeTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunOnce) + internal TimeTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.RunOnce) { } @@ -1850,8 +1851,8 @@ namespace winPEAS.TaskScheduler internal const string V2BoundaryDateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFK"; internal static readonly CultureInfo DefaultDateCulture = CultureInfo.CreateSpecificCulture("en-US"); - internal V1Interop.ITaskTrigger v1Trigger; - internal V1Interop.TaskTrigger v1TriggerData; + internal ITaskTrigger v1Trigger; + internal TaskTrigger v1TriggerData; internal ITrigger v2Trigger; /// In testing and may change. Do not use until officially introduced into library. @@ -1862,7 +1863,7 @@ namespace winPEAS.TaskScheduler private readonly TaskTriggerType ttype; private RepetitionPattern repititionPattern; - internal Trigger([NotNull] V1Interop.ITaskTrigger trigger, V1Interop.TaskTriggerType type) + internal Trigger([NotNull] ITaskTrigger trigger, V1.TaskTriggerType type) { v1Trigger = trigger; v1TriggerData = trigger.GetTrigger(); @@ -1882,7 +1883,7 @@ namespace winPEAS.TaskScheduler { ttype = triggerType; - v1TriggerData.TriggerSize = (ushort)Marshal.SizeOf(typeof(V1Interop.TaskTrigger)); + v1TriggerData.TriggerSize = (ushort)Marshal.SizeOf(typeof(TaskTrigger)); if (ttype != TaskTriggerType.Registration && ttype != TaskTriggerType.Event && ttype != TaskTriggerType.SessionStateChange) v1TriggerData.Type = ConvertToV1TriggerType(ttype); @@ -1896,14 +1897,14 @@ namespace winPEAS.TaskScheduler /// Gets or sets a Boolean value that indicates whether the trigger is enabled. public bool Enabled { - get => v2Trigger?.Enabled ?? GetUnboundValueOrDefault(nameof(Enabled), !v1TriggerData.Flags.IsFlagSet(V1Interop.TaskTriggerFlags.Disabled)); + get => v2Trigger?.Enabled ?? GetUnboundValueOrDefault(nameof(Enabled), !v1TriggerData.Flags.IsFlagSet(TaskTriggerFlags.Disabled)); set { if (v2Trigger != null) v2Trigger.Enabled = value; else { - v1TriggerData.Flags = v1TriggerData.Flags.SetFlags(V1Interop.TaskTriggerFlags.Disabled, !value); + v1TriggerData.Flags = v1TriggerData.Flags.SetFlags(TaskTriggerFlags.Disabled, !value); if (v1Trigger != null) SetV1TriggerData(); else @@ -2258,29 +2259,29 @@ namespace winPEAS.TaskScheduler internal static DateTime AdjustToLocal(DateTime dt) => dt.Kind == DateTimeKind.Utc ? dt.ToLocalTime() : dt; - internal static V1Interop.TaskTriggerType ConvertToV1TriggerType(TaskTriggerType type) + internal static V1.TaskTriggerType ConvertToV1TriggerType(TaskTriggerType type) { if (type == TaskTriggerType.Registration || type == TaskTriggerType.Event || type == TaskTriggerType.SessionStateChange) throw new NotV1SupportedException(); var tv1 = (int)type - 1; if (tv1 >= 7) tv1--; - return (V1Interop.TaskTriggerType)tv1; + return (V1.TaskTriggerType)tv1; } - internal static Trigger CreateTrigger([NotNull] V1Interop.ITaskTrigger trigger) => CreateTrigger(trigger, trigger.GetTrigger().Type); + internal static Trigger CreateTrigger([NotNull] ITaskTrigger trigger) => CreateTrigger(trigger, trigger.GetTrigger().Type); - internal static Trigger CreateTrigger([NotNull] V1Interop.ITaskTrigger trigger, V1Interop.TaskTriggerType triggerType) + internal static Trigger CreateTrigger([NotNull] ITaskTrigger trigger, V1.TaskTriggerType triggerType) { Trigger t = triggerType switch { - V1Interop.TaskTriggerType.RunOnce => new TimeTrigger(trigger), - V1Interop.TaskTriggerType.RunDaily => new DailyTrigger(trigger), - V1Interop.TaskTriggerType.RunWeekly => new WeeklyTrigger(trigger), - V1Interop.TaskTriggerType.RunMonthly => new MonthlyTrigger(trigger), - V1Interop.TaskTriggerType.RunMonthlyDOW => new MonthlyDOWTrigger(trigger), - V1Interop.TaskTriggerType.OnIdle => new IdleTrigger(trigger), - V1Interop.TaskTriggerType.OnSystemStart => new BootTrigger(trigger), - V1Interop.TaskTriggerType.OnLogon => new LogonTrigger(trigger), + V1.TaskTriggerType.RunOnce => new TimeTrigger(trigger), + V1.TaskTriggerType.RunDaily => new DailyTrigger(trigger), + V1.TaskTriggerType.RunWeekly => new WeeklyTrigger(trigger), + V1.TaskTriggerType.RunMonthly => new MonthlyTrigger(trigger), + V1.TaskTriggerType.RunMonthlyDOW => new MonthlyDOWTrigger(trigger), + V1.TaskTriggerType.OnIdle => new IdleTrigger(trigger), + V1.TaskTriggerType.OnSystemStart => new BootTrigger(trigger), + V1.TaskTriggerType.OnLogon => new LogonTrigger(trigger), _ => throw new ArgumentOutOfRangeException(nameof(triggerType), triggerType, null), }; return t; @@ -2365,7 +2366,7 @@ namespace winPEAS.TaskScheduler return span.ToString(); } - internal virtual void Bind([NotNull] V1Interop.ITask iTask) + internal virtual void Bind([NotNull] ITask iTask) { if (v1Trigger == null) { @@ -2443,7 +2444,7 @@ namespace winPEAS.TaskScheduler /// String describing the trigger. protected virtual string V2GetTriggerString() => string.Empty; - private static TaskTriggerType ConvertFromV1TriggerType(V1Interop.TaskTriggerType v1Type) + private static TaskTriggerType ConvertFromV1TriggerType(V1.TaskTriggerType v1Type) { var tv2 = (int)v1Type + 1; if (tv2 > 6) tv2++; @@ -2494,7 +2495,7 @@ namespace winPEAS.TaskScheduler WeeksInterval = weeksInterval; } - internal WeeklyTrigger([NotNull] V1Interop.ITaskTrigger iTrigger) : base(iTrigger, V1Interop.TaskTriggerType.RunWeekly) + internal WeeklyTrigger([NotNull] ITaskTrigger iTrigger) : base(iTrigger, V1.TaskTriggerType.RunWeekly) { if (v1TriggerData.Data.weekly.DaysOfTheWeek == 0) v1TriggerData.Data.weekly.DaysOfTheWeek = DaysOfTheWeek.Sunday; diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TriggerCollection.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TriggerCollection.cs index 8b88ca9..ac4c51e 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/TriggerCollection.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/TriggerCollection.cs @@ -10,7 +10,8 @@ using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using winPEAS.TaskScheduler.TaskEditor.Native; -using winPEAS.TaskScheduler.V1Interop; +using winPEAS.TaskScheduler.V1; +using winPEAS.TaskScheduler.V2; namespace winPEAS.TaskScheduler { @@ -18,14 +19,14 @@ namespace winPEAS.TaskScheduler public sealed class TriggerCollection : IList, IDisposable, IXmlSerializable, IList, INotifyCollectionChanged, INotifyPropertyChanged { private const string IndexerName = "Item[]"; - private readonly V2Interop.ITriggerCollection v2Coll; + private readonly ITriggerCollection v2Coll; private bool inV2set; - private V1Interop.ITask v1Task; - private V2Interop.ITaskDefinition v2Def; + private ITask v1Task; + private ITaskDefinition v2Def; - internal TriggerCollection([NotNull] V1Interop.ITask iTask) => v1Task = iTask; + internal TriggerCollection([NotNull] ITask iTask) => v1Task = iTask; - internal TriggerCollection([NotNull] V2Interop.ITaskDefinition iTaskDef) + internal TriggerCollection([NotNull] ITaskDefinition iTaskDef) { v2Def = iTaskDef; v2Coll = v2Def.Triggers; @@ -337,7 +338,7 @@ namespace winPEAS.TaskScheduler { if (v1Task != null) return new V1TriggerEnumerator(v1Task); - return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], o => Trigger.CreateTrigger(o, v2Def)); + return new ComEnumerator(() => v2Coll.Count, i => v2Coll[i], o => Trigger.CreateTrigger(o, v2Def)); } /// Determines the index of a specific item in the . @@ -518,9 +519,9 @@ namespace winPEAS.TaskScheduler private sealed class V1TriggerEnumerator : IEnumerator { private short curItem = -1; - private V1Interop.ITask iTask; + private ITask iTask; - internal V1TriggerEnumerator(V1Interop.ITask task) => iTask = task; + internal V1TriggerEnumerator(ITask task) => iTask = task; public Trigger Current => Trigger.CreateTrigger(iTask.GetTrigger((ushort)curItem)); diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/V1/TaskSchedulerV1Interop.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/V1/TaskSchedulerV1Interop.cs index 47dd76e..39575fa 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/V1/TaskSchedulerV1Interop.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/V1/TaskSchedulerV1Interop.cs @@ -1,12 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using winPEAS.TaskScheduler.TaskEditor.Native; -namespace winPEAS.TaskScheduler.V1Interop +namespace winPEAS.TaskScheduler.V1 { #pragma warning disable CS0618 // Type or member is obsolete diff --git a/winPEAS/winPEASexe/winPEAS/TaskScheduler/V2/TaskSchedulerV2Interop.cs b/winPEAS/winPEASexe/winPEAS/TaskScheduler/V2/TaskSchedulerV2Interop.cs index f590c06..6c39ac1 100644 --- a/winPEAS/winPEASexe/winPEAS/TaskScheduler/V2/TaskSchedulerV2Interop.cs +++ b/winPEAS/winPEASexe/winPEAS/TaskScheduler/V2/TaskSchedulerV2Interop.cs @@ -1,16 +1,11 @@ using System; using System.Collections; -using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; using winPEAS.TaskScheduler.TaskEditor.Native; -using winPEAS.TaskScheduler.V1Interop; -namespace winPEAS.TaskScheduler.V2Interop +namespace winPEAS.TaskScheduler.V2 { internal enum TaskEnumFlags