Advertisement
Guest User

adreconpt1

a guest
Dec 21st, 2018
510
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 232.75 KB | None | 0 0
  1. <#
  2.  
  3. .SYNOPSIS
  4.  
  5. ADRecon is a tool which gathers information about the Active Directory and generates a report which can provide a holistic picture of the current state of the target AD environment.
  6.  
  7. .DESCRIPTION
  8.  
  9. ADRecon is a tool which extracts and combines various artefacts (as highlighted below) out of an AD environment. The information can be presented in a specially formatted Microsoft Excel report that includes summary views with metrics to facilitate analysis and provide a holistic picture of the current state of the target AD environment.
  10. The tool is useful to various classes of security professionals like auditors, DFIR, students, administrators, etc. It can also be an invaluable post-exploitation tool for a penetration tester.
  11. It can be run from any workstation that is connected to the environment, even hosts that are not domain members. Furthermore, the tool can be executed in the context of a non-privileged (i.e. standard domain user) account.
  12. Fine Grained Password Policy, LAPS and BitLocker may require Privileged user accounts.
  13. The tool will use Microsoft Remote Server Administration Tools (RSAT) if available, otherwise it will communicate with the Domain Controller using LDAP.
  14. The following information is gathered by the tool:
  15. - Forest;
  16. - Domain;
  17. - Trusts;
  18. - Sites;
  19. - Subnets;
  20. - Default and Fine Grained Password Policy (if implemented);
  21. - Domain Controllers, SMB versions, whether SMB Signing is supported and FSMO roles;
  22. - Users and their attributes;
  23. - Service Principal Names (SPNs);
  24. - Groups and memberships;
  25. - Organizational Units (OUs);
  26. - Group Policy Object and gPLink details;
  27. - DNS Zones and Records;
  28. - Printers;
  29. - Computers and their attributes;
  30. - PasswordAttributes (Experimental);
  31. - LAPS passwords (if implemented);
  32. - BitLocker Recovery Keys (if implemented);
  33. - ACLs (DACLs and SACLs) for the Domain, OUs, Root Containers, GPO, Users, Computers and Groups objects;
  34. - GPOReport (requires RSAT);
  35. - Kerberoast (not included in the default collection method); and
  36. - Domain accounts used for service accounts (requires privileged account and not included in the default collection method).
  37.  
  38. Author : Prashant Mahajan
  39. Company : https://www.senseofsecurity.com.au
  40.  
  41. .NOTES
  42.  
  43. The following commands can be used to turn off ExecutionPolicy: (Requires Admin Privs)
  44.  
  45. PS > $ExecPolicy = Get-ExecutionPolicy
  46. PS > Set-ExecutionPolicy bypass
  47. PS > .\ADRecon.ps1
  48. PS > Set-ExecutionPolicy $ExecPolicy
  49.  
  50. OR
  51.  
  52. Start the PowerShell as follows:
  53. powershell.exe -ep bypass
  54.  
  55. OR
  56.  
  57. Already have a PowerShell open ?
  58. PS > $Env:PSExecutionPolicyPreference = 'Bypass'
  59.  
  60. OR
  61.  
  62. powershell.exe -nologo -executionpolicy bypass -noprofile -file ADRecon.ps1
  63.  
  64. .PARAMETER Protocol
  65. Which protocol to use; ADWS (default) or LDAP
  66.  
  67. .PARAMETER DomainController
  68. Domain Controller IP Address or Domain FQDN.
  69.  
  70. .PARAMETER Credential
  71. Domain Credentials.
  72.  
  73. .PARAMETER GenExcel
  74. Path for ADRecon output folder containing the CSV files to generate the ADRecon-Report.xlsx. Use it to generate the ADRecon-Report.xlsx when Microsoft Excel is not installed on the host used to run ADRecon.
  75.  
  76. .PARAMETER OutputDir
  77. Path for ADRecon output folder to save the files and the ADRecon-Report.xlsx. (The folder specified will be created if it doesn't exist)
  78.  
  79. .PARAMETER Collect
  80. Which modules to run; Comma separated; e.g Forest,Domain (Default all except Kerberoast, DomainAccountsusedforServiceLogon)
  81. Valid values include: Forest, Domain, Trusts, Sites, Subnets, PasswordPolicy, FineGrainedPasswordPolicy, DomainControllers, Users, UserSPNs, PasswordAttributes, Groups, GroupMembers, OUs, GPOs, gPLinks, DNSZones, Printers, Computers, ComputerSPNs, LAPS, BitLocker, ACLs, GPOReport, Kerberoast, DomainAccountsusedforServiceLogon.
  82.  
  83. .PARAMETER OutputType
  84. Output Type; Comma seperated; e.g STDOUT,CSV,XML,JSON,HTML,Excel (Default STDOUT with -Collect parameter, else CSV and Excel).
  85. Valid values include: STDOUT, CSV, XML, JSON, HTML, Excel, All (excludes STDOUT).
  86.  
  87. .PARAMETER DormantTimeSpan
  88. Timespan for Dormant accounts. (Default 90 days)
  89.  
  90. .PARAMETER PassMaxAge
  91. Maximum machine account password age. (Default 30 days)
  92.  
  93. .PARAMETER PageSize
  94. The PageSize to set for the LDAP searcher object.
  95.  
  96. .PARAMETER Threads
  97. The number of threads to use during processing objects. (Default 10)
  98.  
  99. .PARAMETER Log
  100. Create ADRecon Log using Start-Transcript
  101.  
  102. .EXAMPLE
  103.  
  104. .\ADRecon.ps1 -GenExcel C:\ADRecon-Report-<timestamp>
  105. [*] ADRecon <version> by Prashant Mahajan (@prashant3535) from Sense of Security.
  106. [*] Generating ADRecon-Report.xlsx
  107. [+] Excelsheet Saved to: C:\ADRecon-Report-<timestamp>\<domain>-ADRecon-Report.xlsx
  108.  
  109. .EXAMPLE
  110.  
  111. .\ADRecon.ps1 -DomainController <IP or FQDN> -Credential <domain\username>
  112. [*] ADRecon <version> by Prashant Mahajan (@prashant3535) from Sense of Security.
  113. [*] Running on <domain>\<hostname> - Member Workstation
  114. <snip>
  115.  
  116. Example output from Domain Member with Alternate Credentials.
  117.  
  118. .EXAMPLE
  119.  
  120. .\ADRecon.ps1 -DomainController <IP or FQDN> -Credential <domain\username> -Collect DomainControllers -OutputType Excel
  121. [*] ADRecon <version> by Prashant Mahajan (@prashant3535) from Sense of Security.
  122. [*] Running on WORKGROUP\<hostname> - Standalone Workstation
  123. [*] Commencing - <timestamp>
  124. [-] Domain Controllers
  125. [*] Total Execution Time (mins): <minutes>
  126. [*] Generating ADRecon-Report.xlsx
  127. [+] Excelsheet Saved to: C:\ADRecon-Report-<timestamp>\<domain>-ADRecon-Report.xlsx
  128. [*] Completed.
  129. [*] Output Directory: C:\ADRecon-Report-<timestamp>
  130.  
  131. Example output from from a Non-Member using RSAT to only enumerate Domain Controllers.
  132.  
  133. .EXAMPLE
  134.  
  135. .\ADRecon.ps1 -Protocol ADWS -DomainController <IP or FQDN> -Credential <domain\username>
  136. [*] ADRecon <version> by Prashant Mahajan (@prashant3535) from Sense of Security.
  137. [*] Running on WORKGROUP\<hostname> - Standalone Workstation
  138. [*] Commencing - <timestamp>
  139. [-] Domain
  140. [-] Forest
  141. [-] Trusts
  142. [-] Sites
  143. [-] Subnets
  144. [-] Default Password Policy
  145. [-] Fine Grained Password Policy - May need a Privileged Account
  146. [-] Domain Controllers
  147. [-] Users - May take some time
  148. [-] User SPNs
  149. [-] PasswordAttributes - Experimental
  150. [-] Groups - May take some time
  151. [-] Group Memberships - May take some time
  152. [-] OrganizationalUnits (OUs)
  153. [-] GPOs
  154. [-] gPLinks - Scope of Management (SOM)
  155. [-] DNS Zones and Records
  156. [-] Printers
  157. [-] Computers - May take some time
  158. [-] Computer SPNs
  159. [-] LAPS - Needs Privileged Account
  160. WARNING: [*] LAPS is not implemented.
  161. [-] BitLocker Recovery Keys - Needs Privileged Account
  162. [-] ACLs - May take some time
  163. WARNING: [*] SACLs - Currently, the module is only supported with LDAP.
  164. [-] GPOReport - May take some time
  165. WARNING: [EXCEPTION] Current security context is not associated with an Active Directory domain or forest.
  166. WARNING: [*] Run the tool using RUNAS.
  167. WARNING: [*] runas /user:<Domain FQDN>\<Username> /netonly powershell.exe
  168. [*] Total Execution Time (mins): <minutes>
  169. [*] Output Directory: C:\ADRecon-Report-<timestamp>
  170. [*] Generating ADRecon-Report.xlsx
  171. [+] Excelsheet Saved to: C:\ADRecon-Report-<timestamp>\<domain>-ADRecon-Report.xlsx
  172.  
  173. Example output from a Non-Member using RSAT.
  174.  
  175. .EXAMPLE
  176.  
  177. .\ADRecon.ps1 -Protocol LDAP -DomainController <IP or FQDN> -Credential <domain\username>
  178. [*] ADRecon <version> by Prashant Mahajan (@prashant3535) from Sense of Security.
  179. [*] Running on WORKGROUP\<hostname> - Standalone Workstation
  180. [*] LDAP bind Successful
  181. [*] Commencing - <timestamp>
  182. [-] Domain
  183. [-] Forest
  184. [-] Trusts
  185. [-] Sites
  186. [-] Subnets
  187. [-] Default Password Policy
  188. [-] Fine Grained Password Policy - May need a Privileged Account
  189. [-] Domain Controllers
  190. [-] Users - May take some time
  191. [-] User SPNs
  192. [-] PasswordAttributes - Experimental
  193. [-] Groups - May take some time
  194. [-] Group Memberships - May take some time
  195. [-] OrganizationalUnits (OUs)
  196. [-] GPOs
  197. [-] gPLinks - Scope of Management (SOM)
  198. [-] DNS Zones and Records
  199. [-] Printers
  200. [-] Computers - May take some time
  201. [-] Computer SPNs
  202. [-] LAPS - Needs Privileged Account
  203. WARNING: [*] LAPS is not implemented.
  204. [-] BitLocker Recovery Keys - Needs Privileged Account
  205. [-] ACLs - May take some time
  206. [-] GPOReport - May take some time
  207. WARNING: [*] Currently, the module is only supported with ADWS.
  208. [*] Total Execution Time (mins): <minutes>
  209. [*] Output Directory: C:\ADRecon-Report-<timestamp>
  210. [*] Generating ADRecon-Report.xlsx
  211. [+] Excelsheet Saved to: C:\ADRecon-Report-<timestamp>\<domain>-ADRecon-Report.xlsx
  212.  
  213. Example output from a Non-Member using LDAP.
  214.  
  215. .LINK
  216.  
  217. https://github.com/sense-of-security/ADRecon
  218. #>
  219.  
  220. [CmdletBinding()]
  221. param
  222. (
  223. [Parameter(Mandatory = $false, HelpMessage = "Which protocol to use; ADWS (default) or LDAP.")]
  224. [ValidateSet('ADWS', 'LDAP')]
  225. [string] $Protocol = 'ADWS',
  226.  
  227. [Parameter(Mandatory = $false, HelpMessage = "Domain Controller IP Address or Domain FQDN.")]
  228. [string] $DomainController = '',
  229.  
  230. [Parameter(Mandatory = $false, HelpMessage = "Domain Credentials.")]
  231. [Management.Automation.PSCredential] $Credential = [Management.Automation.PSCredential]::Empty,
  232.  
  233. [Parameter(Mandatory = $false, HelpMessage = "Path for ADRecon output folder containing the CSV files to generate the ADRecon-Report.xlsx. Use it to generate the ADRecon-Report.xlsx when Microsoft Excel is not installed on the host used to run ADRecon.")]
  234. [string] $GenExcel,
  235.  
  236. [Parameter(Mandatory = $false, HelpMessage = "Path for ADRecon output folder to save the CSV/XML/JSON/HTML files and the ADRecon-Report.xlsx. (The folder specified will be created if it doesn't exist)")]
  237. [string] $OutputDir,
  238.  
  239. [Parameter(Mandatory = $false, HelpMessage = "Which modules to run; Comma separated; e.g Forest,Domain (Default all except Kerberoast, DomainAccountsusedforServiceLogon) Valid values include: Forest, Domain, Trusts, Sites, Subnets, PasswordPolicy, FineGrainedPasswordPolicy, DomainControllers, Users, UserSPNs, PasswordAttributes, Groups, GroupMembers, OUs, GPOs, gPLinks, DNSZones, Printers, Computers, ComputerSPNs, LAPS, BitLocker, ACLs, GPOReport, Kerberoast, DomainAccountsusedforServiceLogon")]
  240. [ValidateSet('Forest', 'Domain', 'Trusts', 'Sites', 'Subnets', 'PasswordPolicy', 'FineGrainedPasswordPolicy', 'DomainControllers', 'Users', 'UserSPNs', 'PasswordAttributes', 'Groups', 'GroupMembers', 'OUs', 'GPOs', 'gPLinks', 'DNSZones', 'Printers', 'Computers', 'ComputerSPNs', 'LAPS', 'BitLocker', 'ACLs', 'GPOReport', 'Kerberoast', 'DomainAccountsusedforServiceLogon', 'Default')]
  241. [array] $Collect = 'Default',
  242.  
  243. [Parameter(Mandatory = $false, HelpMessage = "Output type; Comma seperated; e.g STDOUT,CSV,XML,JSON,HTML,Excel (Default STDOUT with -Collect parameter, else CSV and Excel)")]
  244. [ValidateSet('STDOUT', 'CSV', 'XML', 'JSON', 'EXCEL', 'HTML', 'All', 'Default')]
  245. [array] $OutputType = 'Default',
  246.  
  247. [Parameter(Mandatory = $false, HelpMessage = "Timespan for Dormant accounts. Default 90 days")]
  248. [ValidateRange(1,1000)]
  249. [int] $DormantTimeSpan = 90,
  250.  
  251. [Parameter(Mandatory = $false, HelpMessage = "Maximum machine account password age. Default 30 days")]
  252. [ValidateRange(1,1000)]
  253. [int] $PassMaxAge = 30,
  254.  
  255. [Parameter(Mandatory = $false, HelpMessage = "The PageSize to set for the LDAP searcher object. Default 200")]
  256. [ValidateRange(1,10000)]
  257. [int] $PageSize = 200,
  258.  
  259. [Parameter(Mandatory = $false, HelpMessage = "The number of threads to use during processing of objects. Default 10")]
  260. [ValidateRange(1,100)]
  261. [int] $Threads = 10,
  262.  
  263. [Parameter(Mandatory = $false, HelpMessage = "Create ADRecon Log using Start-Transcript")]
  264. [switch] $Log
  265. )
  266.  
  267. $ADWSSource = @"
  268. // Thanks Dennis Albuquerque for the C# multithreading code
  269. using System;
  270. using System.Collections;
  271. using System.Collections.Generic;
  272. using System.Linq;
  273. using System.Threading;
  274. using System.DirectoryServices;
  275. using System.Security.Principal;
  276. using System.Security.AccessControl;
  277. using System.Management.Automation;
  278.  
  279. namespace ADRecon
  280. {
  281. public static class ADWSClass
  282. {
  283. private static DateTime Date1;
  284. private static int PassMaxAge;
  285. private static int DormantTimeSpan;
  286. private static Dictionary<String, String> AdGroupDictionary = new Dictionary<String, String>();
  287. private static String DomainSID;
  288. private static Dictionary<String, String> AdGPODictionary = new Dictionary<String, String>();
  289. private static Hashtable GUIDs = new Hashtable();
  290. private static Dictionary<String, String> AdSIDDictionary = new Dictionary<String, String>();
  291. private static readonly HashSet<string> Groups = new HashSet<string> ( new String[] {"268435456", "268435457", "536870912", "536870913"} );
  292. private static readonly HashSet<string> Users = new HashSet<string> ( new String[] { "805306368" } );
  293. private static readonly HashSet<string> Computers = new HashSet<string> ( new String[] { "805306369" }) ;
  294. private static readonly HashSet<string> TrustAccounts = new HashSet<string> ( new String[] { "805306370" } );
  295.  
  296. [Flags]
  297. //Values taken from https://support.microsoft.com/en-au/kb/305144
  298. public enum UACFlags
  299. {
  300. SCRIPT = 1, // 0x1
  301. ACCOUNTDISABLE = 2, // 0x2
  302. HOMEDIR_REQUIRED = 8, // 0x8
  303. LOCKOUT = 16, // 0x10
  304. PASSWD_NOTREQD = 32, // 0x20
  305. PASSWD_CANT_CHANGE = 64, // 0x40
  306. ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128, // 0x80
  307. TEMP_DUPLICATE_ACCOUNT = 256, // 0x100
  308. NORMAL_ACCOUNT = 512, // 0x200
  309. INTERDOMAIN_TRUST_ACCOUNT = 2048, // 0x800
  310. WORKSTATION_TRUST_ACCOUNT = 4096, // 0x1000
  311. SERVER_TRUST_ACCOUNT = 8192, // 0x2000
  312. DONT_EXPIRE_PASSWD = 65536, // 0x10000
  313. MNS_LOGON_ACCOUNT = 131072, // 0x20000
  314. SMARTCARD_REQUIRED = 262144, // 0x40000
  315. TRUSTED_FOR_DELEGATION = 524288, // 0x80000
  316. NOT_DELEGATED = 1048576, // 0x100000
  317. USE_DES_KEY_ONLY = 2097152, // 0x200000
  318. DONT_REQUIRE_PREAUTH = 4194304, // 0x400000
  319. PASSWORD_EXPIRED = 8388608, // 0x800000
  320. TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216, // 0x1000000
  321. PARTIAL_SECRETS_ACCOUNT = 67108864 // 0x04000000
  322. }
  323.  
  324. [Flags]
  325. //Values taken from https://blogs.msdn.microsoft.com/openspecification/2011/05/30/windows-configurations-for-kerberos-supported-encryption-type/
  326. public enum KerbEncFlags
  327. {
  328. ZERO = 0,
  329. DES_CBC_CRC = 1, // 0x1
  330. DES_CBC_MD5 = 2, // 0x2
  331. RC4_HMAC = 4, // 0x4
  332. AES128_CTS_HMAC_SHA1_96 = 8, // 0x18
  333. AES256_CTS_HMAC_SHA1_96 = 16 // 0x10
  334. }
  335.  
  336. private static readonly Dictionary<String, String> Replacements = new Dictionary<String, String>()
  337. {
  338. //{System.Environment.NewLine, ""},
  339. //{",", ";"},
  340. {"\"", "'"}
  341. };
  342.  
  343. public static String CleanString(Object StringtoClean)
  344. {
  345. // Remove extra spaces and new lines
  346. String CleanedString = String.Join(" ", ((Convert.ToString(StringtoClean)).Split((string[]) null, StringSplitOptions.RemoveEmptyEntries)));
  347. foreach (String Replacement in Replacements.Keys)
  348. {
  349. CleanedString = CleanedString.Replace(Replacement, Replacements[Replacement]);
  350. }
  351. return CleanedString;
  352. }
  353.  
  354. public static int ObjectCount(Object[] ADRObject)
  355. {
  356. return ADRObject.Length;
  357. }
  358.  
  359. public static Object[] UserParser(Object[] AdUsers, DateTime Date1, int DormantTimeSpan, int PassMaxAge, int numOfThreads)
  360. {
  361. ADWSClass.Date1 = Date1;
  362. ADWSClass.DormantTimeSpan = DormantTimeSpan;
  363. ADWSClass.PassMaxAge = PassMaxAge;
  364.  
  365. Object[] ADRObj = runProcessor(AdUsers, numOfThreads, "Users");
  366. return ADRObj;
  367. }
  368.  
  369. public static Object[] UserSPNParser(Object[] AdUsers, int numOfThreads)
  370. {
  371. Object[] ADRObj = runProcessor(AdUsers, numOfThreads, "UserSPNs");
  372. return ADRObj;
  373. }
  374.  
  375. public static Object[] GroupParser(Object[] AdGroups, int numOfThreads)
  376. {
  377. Object[] ADRObj = runProcessor(AdGroups, numOfThreads, "Groups");
  378. return ADRObj;
  379. }
  380.  
  381. public static Object[] GroupMemberParser(Object[] AdGroups, Object[] AdGroupMembers, String DomainSID, int numOfThreads)
  382. {
  383. ADWSClass.AdGroupDictionary = new Dictionary<String, String>();
  384. runProcessor(AdGroups, numOfThreads, "GroupsDictionary");
  385. ADWSClass.DomainSID = DomainSID;
  386. Object[] ADRObj = runProcessor(AdGroupMembers, numOfThreads, "GroupMembers");
  387. return ADRObj;
  388. }
  389.  
  390. public static Object[] OUParser(Object[] AdOUs, int numOfThreads)
  391. {
  392. Object[] ADRObj = runProcessor(AdOUs, numOfThreads, "OUs");
  393. return ADRObj;
  394. }
  395.  
  396. public static Object[] GPOParser(Object[] AdGPOs, int numOfThreads)
  397. {
  398. Object[] ADRObj = runProcessor(AdGPOs, numOfThreads, "GPOs");
  399. return ADRObj;
  400. }
  401.  
  402. public static Object[] SOMParser(Object[] AdGPOs, Object[] AdSOMs, int numOfThreads)
  403. {
  404. ADWSClass.AdGPODictionary = new Dictionary<String, String>();
  405. runProcessor(AdGPOs, numOfThreads, "GPOsDictionary");
  406. Object[] ADRObj = runProcessor(AdSOMs, numOfThreads, "SOMs");
  407. return ADRObj;
  408. }
  409.  
  410. public static Object[] PrinterParser(Object[] ADPrinters, int numOfThreads)
  411. {
  412. Object[] ADRObj = runProcessor(ADPrinters, numOfThreads, "Printers");
  413. return ADRObj;
  414. }
  415.  
  416. public static Object[] ComputerParser(Object[] AdComputers, DateTime Date1, int DormantTimeSpan, int PassMaxAge, int numOfThreads)
  417. {
  418. ADWSClass.Date1 = Date1;
  419. ADWSClass.DormantTimeSpan = DormantTimeSpan;
  420. ADWSClass.PassMaxAge = PassMaxAge;
  421.  
  422. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "Computers");
  423. return ADRObj;
  424. }
  425.  
  426. public static Object[] ComputerSPNParser(Object[] AdComputers, int numOfThreads)
  427. {
  428. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "ComputerSPNs");
  429. return ADRObj;
  430. }
  431.  
  432. public static Object[] LAPSParser(Object[] AdComputers, int numOfThreads)
  433. {
  434. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "LAPS");
  435. return ADRObj;
  436. }
  437.  
  438. public static Object[] DACLParser(Object[] ADObjects, Object PSGUIDs, int numOfThreads)
  439. {
  440. ADWSClass.AdSIDDictionary = new Dictionary<String, String>();
  441. runProcessor(ADObjects, numOfThreads, "SIDDictionary");
  442. ADWSClass.GUIDs = (Hashtable) PSGUIDs;
  443. Object[] ADRObj = runProcessor(ADObjects, numOfThreads, "DACLs");
  444. return ADRObj;
  445. }
  446.  
  447. public static Object[] SACLParser(Object[] ADObjects, Object PSGUIDs, int numOfThreads)
  448. {
  449. ADWSClass.GUIDs = (Hashtable) PSGUIDs;
  450. Object[] ADRObj = runProcessor(ADObjects, numOfThreads, "SACLs");
  451. return ADRObj;
  452. }
  453.  
  454. static Object[] runProcessor(Object[] arrayToProcess, int numOfThreads, string processorType)
  455. {
  456. int totalRecords = arrayToProcess.Length;
  457. IRecordProcessor recordProcessor = recordProcessorFactory(processorType);
  458. IResultsHandler resultsHandler = new SimpleResultsHandler ();
  459. int numberOfRecordsPerThread = totalRecords / numOfThreads;
  460. int remainders = totalRecords % numOfThreads;
  461.  
  462. Thread[] threads = new Thread[numOfThreads];
  463. for (int i = 0; i < numOfThreads; i++)
  464. {
  465. int numberOfRecordsToProcess = numberOfRecordsPerThread;
  466. if (i == (numOfThreads - 1))
  467. {
  468. //last thread, do the remaining records
  469. numberOfRecordsToProcess += remainders;
  470. }
  471.  
  472. //split the full array into chunks to be given to different threads
  473. Object[] sliceToProcess = new Object[numberOfRecordsToProcess];
  474. Array.Copy(arrayToProcess, i * numberOfRecordsPerThread, sliceToProcess, 0, numberOfRecordsToProcess);
  475. ProcessorThread processorThread = new ProcessorThread(i, recordProcessor, resultsHandler, sliceToProcess);
  476. threads[i] = new Thread(processorThread.processThreadRecords);
  477. threads[i].Start();
  478. }
  479. foreach (Thread t in threads)
  480. {
  481. t.Join();
  482. }
  483.  
  484. return resultsHandler.finalise();
  485. }
  486.  
  487. static IRecordProcessor recordProcessorFactory(String name)
  488. {
  489. switch (name)
  490. {
  491. case "Users":
  492. return new UserRecordProcessor();
  493. case "UserSPNs":
  494. return new UserSPNRecordProcessor();
  495. case "Groups":
  496. return new GroupRecordProcessor();
  497. case "GroupsDictionary":
  498. return new GroupRecordDictionaryProcessor();
  499. case "GroupMembers":
  500. return new GroupMemberRecordProcessor();
  501. case "OUs":
  502. return new OURecordProcessor();
  503. case "GPOs":
  504. return new GPORecordProcessor();
  505. case "GPOsDictionary":
  506. return new GPORecordDictionaryProcessor();
  507. case "SOMs":
  508. return new SOMRecordProcessor();
  509. case "Printers":
  510. return new PrinterRecordProcessor();
  511. case "Computers":
  512. return new ComputerRecordProcessor();
  513. case "ComputerSPNs":
  514. return new ComputerSPNRecordProcessor();
  515. case "LAPS":
  516. return new LAPSRecordProcessor();
  517. case "SIDDictionary":
  518. return new SIDRecordDictionaryProcessor();
  519. case "DACLs":
  520. return new DACLRecordProcessor();
  521. case "SACLs":
  522. return new SACLRecordProcessor();
  523. }
  524. throw new ArgumentException("Invalid processor type " + name);
  525. }
  526.  
  527. class ProcessorThread
  528. {
  529. readonly int id;
  530. readonly IRecordProcessor recordProcessor;
  531. readonly IResultsHandler resultsHandler;
  532. readonly Object[] objectsToBeProcessed;
  533.  
  534. public ProcessorThread(int id, IRecordProcessor recordProcessor, IResultsHandler resultsHandler, Object[] objectsToBeProcessed)
  535. {
  536. this.recordProcessor = recordProcessor;
  537. this.id = id;
  538. this.resultsHandler = resultsHandler;
  539. this.objectsToBeProcessed = objectsToBeProcessed;
  540. }
  541.  
  542. public void processThreadRecords()
  543. {
  544. for (int i = 0; i < objectsToBeProcessed.Length; i++)
  545. {
  546. Object[] result = recordProcessor.processRecord(objectsToBeProcessed[i]);
  547. resultsHandler.processResults(result); //this is a thread safe operation
  548. }
  549. }
  550. }
  551.  
  552. //The interface and implmentation class used to process a record (this implemmentation just returns a log type string)
  553.  
  554. interface IRecordProcessor
  555. {
  556. PSObject[] processRecord(Object record);
  557. }
  558.  
  559. class UserRecordProcessor : IRecordProcessor
  560. {
  561. public PSObject[] processRecord(Object record)
  562. {
  563. try
  564. {
  565. PSObject AdUser = (PSObject) record;
  566. bool? Enabled = null;
  567. bool MustChangePasswordatLogon = false;
  568. bool PasswordNotChangedafterMaxAge = false;
  569. bool NeverLoggedIn = false;
  570. int? DaysSinceLastLogon = null;
  571. int? DaysSinceLastPasswordChange = null;
  572. int? AccountExpirationNumofDays = null;
  573. bool Dormant = false;
  574. String SIDHistory = "";
  575. bool? KerberosRC4 = null;
  576. bool? KerberosAES128 = null;
  577. bool? KerberosAES256 = null;
  578. String DelegationType = null;
  579. String DelegationProtocol = null;
  580. String DelegationServices = null;
  581. DateTime? LastLogonDate = null;
  582. DateTime? PasswordLastSet = null;
  583. DateTime? AccountExpires = null;
  584.  
  585. try
  586. {
  587. // The Enabled field can be blank which raises an exception. This may occur when the user is not allowed to query the UserAccountControl attribute.
  588. Enabled = (bool) AdUser.Members["Enabled"].Value;
  589. }
  590. catch //(Exception e)
  591. {
  592. //Console.WriteLine("{0} Exception caught.", e);
  593. }
  594. if (AdUser.Members["lastLogonTimeStamp"].Value != null)
  595. {
  596. //LastLogonDate = DateTime.FromFileTime((long)(AdUser.Members["lastLogonTimeStamp"].Value));
  597. // LastLogonDate is lastLogonTimeStamp converted to local time
  598. LastLogonDate = Convert.ToDateTime(AdUser.Members["LastLogonDate"].Value);
  599. DaysSinceLastLogon = Math.Abs((Date1 - (DateTime)LastLogonDate).Days);
  600. if (DaysSinceLastLogon > DormantTimeSpan)
  601. {
  602. Dormant = true;
  603. }
  604. }
  605. else
  606. {
  607. NeverLoggedIn = true;
  608. }
  609. if (Convert.ToString(AdUser.Members["pwdLastSet"].Value) == "0")
  610. {
  611. if ((bool) AdUser.Members["PasswordNeverExpires"].Value == false)
  612. {
  613. MustChangePasswordatLogon = true;
  614. }
  615. }
  616. if (AdUser.Members["PasswordLastSet"].Value != null)
  617. {
  618. //PasswordLastSet = DateTime.FromFileTime((long)(AdUser.Members["pwdLastSet"].Value));
  619. // PasswordLastSet is pwdLastSet converted to local time
  620. PasswordLastSet = Convert.ToDateTime(AdUser.Members["PasswordLastSet"].Value);
  621. DaysSinceLastPasswordChange = Math.Abs((Date1 - (DateTime)PasswordLastSet).Days);
  622. if (DaysSinceLastPasswordChange > PassMaxAge)
  623. {
  624. PasswordNotChangedafterMaxAge = true;
  625. }
  626. }
  627. //https://msdn.microsoft.com/en-us/library/ms675098(v=vs.85).aspx
  628. //if ((Int64) AdUser.Members["accountExpires"].Value != (Int64) 9223372036854775807)
  629. //{
  630. //if ((Int64) AdUser.Members["accountExpires"].Value != (Int64) 0)
  631. if (AdUser.Members["AccountExpirationDate"].Value != null)
  632. {
  633. try
  634. {
  635. //AccountExpires = DateTime.FromFileTime((long)(AdUser.Members["accountExpires"].Value));
  636. // AccountExpirationDate is accountExpires converted to local time
  637. AccountExpires = Convert.ToDateTime(AdUser.Members["AccountExpirationDate"].Value);
  638. AccountExpirationNumofDays = ((int)((DateTime)AccountExpires - Date1).Days);
  639.  
  640. }
  641. catch //(Exception e)
  642. {
  643. //Console.WriteLine("{0} Exception caught.", e);
  644. }
  645. }
  646. //}
  647. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection history = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) AdUser.Members["SIDHistory"].Value;
  648. if (history.Value is System.Security.Principal.SecurityIdentifier[])
  649. {
  650. string sids = "";
  651. foreach (var value in (SecurityIdentifier[]) history.Value)
  652. {
  653. sids = sids + "," + Convert.ToString(value);
  654. }
  655. SIDHistory = sids.TrimStart(',');
  656. }
  657. else
  658. {
  659. SIDHistory = history != null ? Convert.ToString(history.Value) : "";
  660. }
  661. if (AdUser.Members["msDS-SupportedEncryptionTypes"].Value != null)
  662. {
  663. var userKerbEncFlags = (KerbEncFlags) AdUser.Members["msDS-SupportedEncryptionTypes"].Value;
  664. if (userKerbEncFlags != KerbEncFlags.ZERO)
  665. {
  666. KerberosRC4 = (userKerbEncFlags & KerbEncFlags.RC4_HMAC) == KerbEncFlags.RC4_HMAC;
  667. KerberosAES128 = (userKerbEncFlags & KerbEncFlags.AES128_CTS_HMAC_SHA1_96) == KerbEncFlags.AES128_CTS_HMAC_SHA1_96;
  668. KerberosAES256 = (userKerbEncFlags & KerbEncFlags.AES256_CTS_HMAC_SHA1_96) == KerbEncFlags.AES256_CTS_HMAC_SHA1_96;
  669. }
  670. }
  671. if ((bool) AdUser.Members["TrustedForDelegation"].Value)
  672. {
  673. DelegationType = "Unconstrained";
  674. DelegationServices = "Any";
  675. }
  676. if (AdUser.Members["msDS-AllowedToDelegateTo"] != null)
  677. {
  678. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection delegateto = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) AdUser.Members["msDS-AllowedToDelegateTo"].Value;
  679. if (delegateto.Value != null)
  680. {
  681. DelegationType = "Constrained";
  682. if (delegateto.Value is System.String[])
  683. {
  684. foreach (var value in (String[]) delegateto.Value)
  685. {
  686. DelegationServices = DelegationServices + "," + Convert.ToString(value);
  687. }
  688. DelegationServices = DelegationServices.TrimStart(',');
  689. }
  690. else
  691. {
  692. DelegationServices = Convert.ToString(delegateto.Value);
  693. }
  694. }
  695. }
  696. if ((bool) AdUser.Members["TrustedToAuthForDelegation"].Value == true)
  697. {
  698. DelegationProtocol = "Any";
  699. }
  700. else if (DelegationType != null)
  701. {
  702. DelegationProtocol = "Kerberos";
  703. }
  704.  
  705. PSObject UserObj = new PSObject();
  706. UserObj.Members.Add(new PSNoteProperty("UserName", AdUser.Members["SamAccountName"].Value));
  707. UserObj.Members.Add(new PSNoteProperty("Name", CleanString(AdUser.Members["Name"].Value)));
  708. UserObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  709. UserObj.Members.Add(new PSNoteProperty("Must Change Password at Logon", MustChangePasswordatLogon));
  710. UserObj.Members.Add(new PSNoteProperty("Cannot Change Password", AdUser.Members["CannotChangePassword"].Value));
  711. UserObj.Members.Add(new PSNoteProperty("Password Never Expires", AdUser.Members["PasswordNeverExpires"].Value));
  712. UserObj.Members.Add(new PSNoteProperty("Reversible Password Encryption", AdUser.Members["AllowReversiblePasswordEncryption"].Value));
  713. UserObj.Members.Add(new PSNoteProperty("Smartcard Logon Required", AdUser.Members["SmartcardLogonRequired"].Value));
  714. UserObj.Members.Add(new PSNoteProperty("Delegation Permitted", !((bool) AdUser.Members["AccountNotDelegated"].Value)));
  715. UserObj.Members.Add(new PSNoteProperty("Kerberos DES Only", AdUser.Members["UseDESKeyOnly"].Value));
  716. UserObj.Members.Add(new PSNoteProperty("Kerberos RC4", KerberosRC4));
  717. UserObj.Members.Add(new PSNoteProperty("Kerberos AES-128bit", KerberosAES128));
  718. UserObj.Members.Add(new PSNoteProperty("Kerberos AES-256bit", KerberosAES256));
  719. UserObj.Members.Add(new PSNoteProperty("Does Not Require Pre Auth", AdUser.Members["DoesNotRequirePreAuth"].Value));
  720. UserObj.Members.Add(new PSNoteProperty("Never Logged in", NeverLoggedIn));
  721. UserObj.Members.Add(new PSNoteProperty("Logon Age (days)", DaysSinceLastLogon));
  722. UserObj.Members.Add(new PSNoteProperty("Password Age (days)", DaysSinceLastPasswordChange));
  723. UserObj.Members.Add(new PSNoteProperty("Dormant (> " + DormantTimeSpan + " days)", Dormant));
  724. UserObj.Members.Add(new PSNoteProperty("Password Age (> " + PassMaxAge + " days)", PasswordNotChangedafterMaxAge));
  725. UserObj.Members.Add(new PSNoteProperty("Account Locked Out", AdUser.Members["LockedOut"].Value));
  726. UserObj.Members.Add(new PSNoteProperty("Password Expired", AdUser.Members["PasswordExpired"].Value));
  727. UserObj.Members.Add(new PSNoteProperty("Password Not Required", AdUser.Members["PasswordNotRequired"].Value));
  728. UserObj.Members.Add(new PSNoteProperty("Delegation Type", DelegationType));
  729. UserObj.Members.Add(new PSNoteProperty("Delegation Protocol", DelegationProtocol));
  730. UserObj.Members.Add(new PSNoteProperty("Delegation Services", DelegationServices));
  731. UserObj.Members.Add(new PSNoteProperty("Logon Workstations", AdUser.Members["LogonWorkstations"].Value));
  732. UserObj.Members.Add(new PSNoteProperty("AdminCount", AdUser.Members["AdminCount"].Value));
  733. UserObj.Members.Add(new PSNoteProperty("Primary GroupID", AdUser.Members["primaryGroupID"].Value));
  734. UserObj.Members.Add(new PSNoteProperty("SID", AdUser.Members["SID"].Value));
  735. UserObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  736. UserObj.Members.Add(new PSNoteProperty("Description", CleanString(AdUser.Members["Description"].Value)));
  737. UserObj.Members.Add(new PSNoteProperty("Title", CleanString(AdUser.Members["Title"].Value)));
  738. UserObj.Members.Add(new PSNoteProperty("Department", CleanString(AdUser.Members["Department"].Value)));
  739. UserObj.Members.Add(new PSNoteProperty("Company", CleanString(AdUser.Members["Company"].Value)));
  740. UserObj.Members.Add(new PSNoteProperty("Manager", CleanString(AdUser.Members["Manager"].Value)));
  741. UserObj.Members.Add(new PSNoteProperty("Info", CleanString(AdUser.Members["Info"].Value)));
  742. UserObj.Members.Add(new PSNoteProperty("Last Logon Date", LastLogonDate));
  743. UserObj.Members.Add(new PSNoteProperty("Password LastSet", PasswordLastSet));
  744. UserObj.Members.Add(new PSNoteProperty("Account Expiration Date", AccountExpires));
  745. UserObj.Members.Add(new PSNoteProperty("Account Expiration (days)", AccountExpirationNumofDays));
  746. UserObj.Members.Add(new PSNoteProperty("Mobile", CleanString(AdUser.Members["Mobile"].Value)));
  747. UserObj.Members.Add(new PSNoteProperty("Email", CleanString(AdUser.Members["mail"].Value)));
  748. UserObj.Members.Add(new PSNoteProperty("HomeDirectory", AdUser.Members["homeDirectory"].Value));
  749. UserObj.Members.Add(new PSNoteProperty("ProfilePath", AdUser.Members["profilePath"].Value));
  750. UserObj.Members.Add(new PSNoteProperty("ScriptPath", AdUser.Members["ScriptPath"].Value));
  751. UserObj.Members.Add(new PSNoteProperty("UserAccountControl", AdUser.Members["UserAccountControl"].Value));
  752. UserObj.Members.Add(new PSNoteProperty("First Name", CleanString(AdUser.Members["givenName"].Value)));
  753. UserObj.Members.Add(new PSNoteProperty("Middle Name", CleanString(AdUser.Members["middleName"].Value)));
  754. UserObj.Members.Add(new PSNoteProperty("Last Name", CleanString(AdUser.Members["sn"].Value)));
  755. UserObj.Members.Add(new PSNoteProperty("Country", CleanString(AdUser.Members["c"].Value)));
  756. UserObj.Members.Add(new PSNoteProperty("whenCreated", AdUser.Members["whenCreated"].Value));
  757. UserObj.Members.Add(new PSNoteProperty("whenChanged", AdUser.Members["whenChanged"].Value));
  758. UserObj.Members.Add(new PSNoteProperty("DistinguishedName", CleanString(AdUser.Members["DistinguishedName"].Value)));
  759. UserObj.Members.Add(new PSNoteProperty("CanonicalName", AdUser.Members["CanonicalName"].Value));
  760. return new PSObject[] { UserObj };
  761. }
  762. catch (Exception e)
  763. {
  764. Console.WriteLine("{0} Exception caught.", e);
  765. return new PSObject[] { };
  766. }
  767. }
  768. }
  769.  
  770. class UserSPNRecordProcessor : IRecordProcessor
  771. {
  772. public PSObject[] processRecord(Object record)
  773. {
  774. try
  775. {
  776. PSObject AdUser = (PSObject) record;
  777. List<PSObject> SPNList = new List<PSObject>();
  778. bool? Enabled = null;
  779. String Memberof = null;
  780. DateTime? PasswordLastSet = null;
  781.  
  782. // When the user is not allowed to query the UserAccountControl attribute.
  783. if (AdUser.Members["userAccountControl"].Value != null)
  784. {
  785. var userFlags = (UACFlags) AdUser.Members["userAccountControl"].Value;
  786. Enabled = !((userFlags & UACFlags.ACCOUNTDISABLE) == UACFlags.ACCOUNTDISABLE);
  787. }
  788. if (Convert.ToString(AdUser.Members["pwdLastSet"].Value) != "0")
  789. {
  790. PasswordLastSet = DateTime.FromFileTime((long)AdUser.Members["pwdLastSet"].Value);
  791. }
  792. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection SPNs = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdUser.Members["servicePrincipalName"].Value;
  793. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection MemberOfAttribute = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdUser.Members["memberof"].Value;
  794. if (MemberOfAttribute.Value is System.String[])
  795. {
  796. foreach (String Member in (System.String[])MemberOfAttribute.Value)
  797. {
  798. Memberof = Memberof + "," + ((Convert.ToString(Member)).Split(',')[0]).Split('=')[1];
  799. }
  800. Memberof = Memberof.TrimStart(',');
  801. }
  802. else if (Memberof != null)
  803. {
  804. Memberof = ((Convert.ToString(MemberOfAttribute.Value)).Split(',')[0]).Split('=')[1];
  805. }
  806. String Description = CleanString(AdUser.Members["Description"].Value);
  807. String PrimaryGroupID = Convert.ToString(AdUser.Members["primaryGroupID"].Value);
  808. if (SPNs.Value is System.String[])
  809. {
  810. foreach (String SPN in (System.String[])SPNs.Value)
  811. {
  812. String[] SPNArray = SPN.Split('/');
  813. PSObject UserSPNObj = new PSObject();
  814. UserSPNObj.Members.Add(new PSNoteProperty("Name", AdUser.Members["Name"].Value));
  815. UserSPNObj.Members.Add(new PSNoteProperty("Username", AdUser.Members["SamAccountName"].Value));
  816. UserSPNObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  817. UserSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  818. UserSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  819. UserSPNObj.Members.Add(new PSNoteProperty("Password Last Set", PasswordLastSet));
  820. UserSPNObj.Members.Add(new PSNoteProperty("Description", Description));
  821. UserSPNObj.Members.Add(new PSNoteProperty("Primary GroupID", PrimaryGroupID));
  822. UserSPNObj.Members.Add(new PSNoteProperty("Memberof", Memberof));
  823. SPNList.Add( UserSPNObj );
  824. }
  825. }
  826. else
  827. {
  828. String[] SPNArray = Convert.ToString(SPNs.Value).Split('/');
  829. PSObject UserSPNObj = new PSObject();
  830. UserSPNObj.Members.Add(new PSNoteProperty("Name", AdUser.Members["Name"].Value));
  831. UserSPNObj.Members.Add(new PSNoteProperty("Username", AdUser.Members["SamAccountName"].Value));
  832. UserSPNObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  833. UserSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  834. UserSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  835. UserSPNObj.Members.Add(new PSNoteProperty("Password Last Set", PasswordLastSet));
  836. UserSPNObj.Members.Add(new PSNoteProperty("Description", Description));
  837. UserSPNObj.Members.Add(new PSNoteProperty("Primary GroupID", PrimaryGroupID));
  838. UserSPNObj.Members.Add(new PSNoteProperty("Memberof", Memberof));
  839. SPNList.Add( UserSPNObj );
  840. }
  841. return SPNList.ToArray();
  842. }
  843. catch (Exception e)
  844. {
  845. Console.WriteLine("{0} Exception caught.", e);
  846. return new PSObject[] { };
  847. }
  848. }
  849. }
  850.  
  851. class GroupRecordProcessor : IRecordProcessor
  852. {
  853. public PSObject[] processRecord(Object record)
  854. {
  855. try
  856. {
  857. PSObject AdGroup = (PSObject) record;
  858. string ManagedByValue = Convert.ToString(AdGroup.Members["managedBy"].Value);
  859. string ManagedBy = "";
  860. String SIDHistory = "";
  861.  
  862. if (AdGroup.Members["managedBy"].Value != null)
  863. {
  864. ManagedBy = (ManagedByValue.Split(',')[0]).Split('=')[1];
  865. }
  866. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection history = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) AdGroup.Members["SIDHistory"].Value;
  867. if (history.Value is System.Security.Principal.SecurityIdentifier[])
  868. {
  869. string sids = "";
  870. foreach (var value in (SecurityIdentifier[]) history.Value)
  871. {
  872. sids = sids + "," + Convert.ToString(value);
  873. }
  874. SIDHistory = sids.TrimStart(',');
  875. }
  876. else
  877. {
  878. SIDHistory = history != null ? Convert.ToString(history.Value) : "";
  879. }
  880.  
  881. PSObject GroupObj = new PSObject();
  882. GroupObj.Members.Add(new PSNoteProperty("Name", AdGroup.Members["SamAccountName"].Value));
  883. GroupObj.Members.Add(new PSNoteProperty("AdminCount", AdGroup.Members["AdminCount"].Value));
  884. GroupObj.Members.Add(new PSNoteProperty("GroupCategory", AdGroup.Members["GroupCategory"].Value));
  885. GroupObj.Members.Add(new PSNoteProperty("GroupScope", AdGroup.Members["GroupScope"].Value));
  886. GroupObj.Members.Add(new PSNoteProperty("ManagedBy", ManagedBy));
  887. GroupObj.Members.Add(new PSNoteProperty("SID", AdGroup.Members["sid"].Value));
  888. GroupObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  889. GroupObj.Members.Add(new PSNoteProperty("Description", CleanString(AdGroup.Members["Description"].Value)));
  890. GroupObj.Members.Add(new PSNoteProperty("whenCreated", AdGroup.Members["whenCreated"].Value));
  891. GroupObj.Members.Add(new PSNoteProperty("whenChanged", AdGroup.Members["whenChanged"].Value));
  892. GroupObj.Members.Add(new PSNoteProperty("DistinguishedName", CleanString(AdGroup.Members["DistinguishedName"].Value)));
  893. GroupObj.Members.Add(new PSNoteProperty("CanonicalName", AdGroup.Members["CanonicalName"].Value));
  894. return new PSObject[] { GroupObj };
  895. }
  896. catch (Exception e)
  897. {
  898. Console.WriteLine("{0} Exception caught.", e);
  899. return new PSObject[] { };
  900. }
  901. }
  902. }
  903.  
  904.  
  905. class GroupRecordDictionaryProcessor : IRecordProcessor
  906. {
  907. public PSObject[] processRecord(Object record)
  908. {
  909. try
  910. {
  911. PSObject AdGroup = (PSObject) record;
  912. ADWSClass.AdGroupDictionary.Add((Convert.ToString(AdGroup.Properties["SID"].Value)), (Convert.ToString(AdGroup.Members["SamAccountName"].Value)));
  913. return new PSObject[] { };
  914. }
  915. catch (Exception e)
  916. {
  917. Console.WriteLine("{0} Exception caught.", e);
  918. return new PSObject[] { };
  919. }
  920. }
  921. }
  922.  
  923. class GroupMemberRecordProcessor : IRecordProcessor
  924. {
  925. public PSObject[] processRecord(Object record)
  926. {
  927. try
  928. {
  929. // based on https://github.com/BloodHoundAD/BloodHound/blob/master/PowerShell/BloodHound.ps1
  930. PSObject AdGroup = (PSObject) record;
  931. List<PSObject> GroupsList = new List<PSObject>();
  932. string SamAccountType = Convert.ToString(AdGroup.Members["samaccounttype"].Value);
  933. string AccountType = "";
  934. string GroupName = "";
  935. string MemberUserName = "-";
  936. string MemberName = "";
  937.  
  938. if (Groups.Contains(SamAccountType))
  939. {
  940. AccountType = "group";
  941. MemberName = ((Convert.ToString(AdGroup.Members["DistinguishedName"].Value)).Split(',')[0]).Split('=')[1];
  942. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection MemberGroups = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdGroup.Members["memberof"].Value;
  943. if (MemberGroups.Value != null)
  944. {
  945. if (MemberGroups.Value is System.String[])
  946. {
  947. foreach (String GroupMember in (System.String[])MemberGroups.Value)
  948. {
  949. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  950. PSObject GroupMemberObj = new PSObject();
  951. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  952. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  953. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  954. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  955. GroupsList.Add( GroupMemberObj );
  956. }
  957. }
  958. else
  959. {
  960. GroupName = (Convert.ToString(MemberGroups.Value).Split(',')[0]).Split('=')[1];
  961. PSObject GroupMemberObj = new PSObject();
  962. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  963. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  964. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  965. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  966. GroupsList.Add( GroupMemberObj );
  967. }
  968. }
  969. }
  970. if (Users.Contains(SamAccountType))
  971. {
  972. AccountType = "user";
  973. MemberName = ((Convert.ToString(AdGroup.Members["DistinguishedName"].Value)).Split(',')[0]).Split('=')[1];
  974. MemberUserName = Convert.ToString(AdGroup.Members["sAMAccountName"].Value);
  975. String PrimaryGroupID = Convert.ToString(AdGroup.Members["primaryGroupID"].Value);
  976. try
  977. {
  978. GroupName = ADWSClass.AdGroupDictionary[ADWSClass.DomainSID + "-" + PrimaryGroupID];
  979. }
  980. catch //(Exception e)
  981. {
  982. //Console.WriteLine("{0} Exception caught.", e);
  983. GroupName = PrimaryGroupID;
  984. }
  985.  
  986. {
  987. PSObject GroupMemberObj = new PSObject();
  988. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  989. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  990. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  991. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  992. GroupsList.Add( GroupMemberObj );
  993. }
  994.  
  995. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection MemberGroups = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdGroup.Members["memberof"].Value;
  996. if (MemberGroups.Value != null)
  997. {
  998. if (MemberGroups.Value is System.String[])
  999. {
  1000. foreach (String GroupMember in (System.String[])MemberGroups.Value)
  1001. {
  1002. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  1003. PSObject GroupMemberObj = new PSObject();
  1004. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  1005. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  1006. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  1007. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  1008. GroupsList.Add( GroupMemberObj );
  1009. }
  1010. }
  1011. else
  1012. {
  1013. GroupName = (Convert.ToString(MemberGroups.Value).Split(',')[0]).Split('=')[1];
  1014. PSObject GroupMemberObj = new PSObject();
  1015. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  1016. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  1017. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  1018. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  1019. GroupsList.Add( GroupMemberObj );
  1020. }
  1021. }
  1022. }
  1023. if (Computers.Contains(SamAccountType))
  1024. {
  1025. AccountType = "computer";
  1026. MemberName = ((Convert.ToString(AdGroup.Members["DistinguishedName"].Value)).Split(',')[0]).Split('=')[1];
  1027. MemberUserName = Convert.ToString(AdGroup.Members["sAMAccountName"].Value);
  1028. String PrimaryGroupID = Convert.ToString(AdGroup.Members["primaryGroupID"].Value);
  1029. try
  1030. {
  1031. GroupName = ADWSClass.AdGroupDictionary[ADWSClass.DomainSID + "-" + PrimaryGroupID];
  1032. }
  1033. catch //(Exception e)
  1034. {
  1035. //Console.WriteLine("{0} Exception caught.", e);
  1036. GroupName = PrimaryGroupID;
  1037. }
  1038.  
  1039. {
  1040. PSObject GroupMemberObj = new PSObject();
  1041. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  1042. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  1043. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  1044. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  1045. GroupsList.Add( GroupMemberObj );
  1046. }
  1047.  
  1048. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection MemberGroups = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdGroup.Members["memberof"].Value;
  1049. if (MemberGroups.Value != null)
  1050. {
  1051. if (MemberGroups.Value is System.String[])
  1052. {
  1053. foreach (String GroupMember in (System.String[])MemberGroups.Value)
  1054. {
  1055. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  1056. PSObject GroupMemberObj = new PSObject();
  1057. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  1058. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  1059. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  1060. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  1061. GroupsList.Add( GroupMemberObj );
  1062. }
  1063. }
  1064. else
  1065. {
  1066. GroupName = (Convert.ToString(MemberGroups.Value).Split(',')[0]).Split('=')[1];
  1067. PSObject GroupMemberObj = new PSObject();
  1068. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  1069. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  1070. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  1071. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  1072. GroupsList.Add( GroupMemberObj );
  1073. }
  1074. }
  1075. }
  1076. if (TrustAccounts.Contains(SamAccountType))
  1077. {
  1078. // TO DO
  1079. }
  1080. return GroupsList.ToArray();
  1081. }
  1082. catch (Exception e)
  1083. {
  1084. Console.WriteLine("{0} Exception caught.", e);
  1085. return new PSObject[] { };
  1086. }
  1087. }
  1088. }
  1089.  
  1090. class OURecordProcessor : IRecordProcessor
  1091. {
  1092. public PSObject[] processRecord(Object record)
  1093. {
  1094. try
  1095. {
  1096. PSObject AdOU = (PSObject) record;
  1097. PSObject OUObj = new PSObject();
  1098. OUObj.Members.Add(new PSNoteProperty("Name", AdOU.Members["Name"].Value));
  1099. OUObj.Members.Add(new PSNoteProperty("Depth", ((Convert.ToString(AdOU.Members["DistinguishedName"].Value).Split(new string[] { "OU=" }, StringSplitOptions.None)).Length -1)));
  1100. OUObj.Members.Add(new PSNoteProperty("Description", AdOU.Members["Description"].Value));
  1101. OUObj.Members.Add(new PSNoteProperty("whenCreated", AdOU.Members["whenCreated"].Value));
  1102. OUObj.Members.Add(new PSNoteProperty("whenChanged", AdOU.Members["whenChanged"].Value));
  1103. OUObj.Members.Add(new PSNoteProperty("DistinguishedName", AdOU.Members["DistinguishedName"].Value));
  1104. return new PSObject[] { OUObj };
  1105. }
  1106. catch (Exception e)
  1107. {
  1108. Console.WriteLine("{0} Exception caught.", e);
  1109. return new PSObject[] { };
  1110. }
  1111. }
  1112. }
  1113.  
  1114. class GPORecordProcessor : IRecordProcessor
  1115. {
  1116. public PSObject[] processRecord(Object record)
  1117. {
  1118. try
  1119. {
  1120. PSObject AdGPO = (PSObject) record;
  1121.  
  1122. PSObject GPOObj = new PSObject();
  1123. GPOObj.Members.Add(new PSNoteProperty("DisplayName", CleanString(AdGPO.Members["DisplayName"].Value)));
  1124. GPOObj.Members.Add(new PSNoteProperty("GUID", CleanString(AdGPO.Members["Name"].Value)));
  1125. GPOObj.Members.Add(new PSNoteProperty("whenCreated", AdGPO.Members["whenCreated"].Value));
  1126. GPOObj.Members.Add(new PSNoteProperty("whenChanged", AdGPO.Members["whenChanged"].Value));
  1127. GPOObj.Members.Add(new PSNoteProperty("DistinguishedName", CleanString(AdGPO.Members["DistinguishedName"].Value)));
  1128. GPOObj.Members.Add(new PSNoteProperty("FilePath", AdGPO.Members["gPCFileSysPath"].Value));
  1129. return new PSObject[] { GPOObj };
  1130. }
  1131. catch (Exception e)
  1132. {
  1133. Console.WriteLine("{0} Exception caught.", e);
  1134. return new PSObject[] { };
  1135. }
  1136. }
  1137. }
  1138.  
  1139. class GPORecordDictionaryProcessor : IRecordProcessor
  1140. {
  1141. public PSObject[] processRecord(Object record)
  1142. {
  1143. try
  1144. {
  1145. PSObject AdGPO = (PSObject) record;
  1146. ADWSClass.AdGPODictionary.Add((Convert.ToString(AdGPO.Members["DistinguishedName"].Value).ToUpper()), (Convert.ToString(AdGPO.Members["DisplayName"].Value)));
  1147. return new PSObject[] { };
  1148. }
  1149. catch (Exception e)
  1150. {
  1151. Console.WriteLine("{0} Exception caught.", e);
  1152. return new PSObject[] { };
  1153. }
  1154. }
  1155. }
  1156.  
  1157. class SOMRecordProcessor : IRecordProcessor
  1158. {
  1159. public PSObject[] processRecord(Object record)
  1160. {
  1161. try
  1162. {
  1163. PSObject AdSOM = (PSObject) record;
  1164. List<PSObject> SOMsList = new List<PSObject>();
  1165. int Depth = 0;
  1166. bool BlockInheritance = false;
  1167. bool? LinkEnabled = null;
  1168. bool? Enforced = null;
  1169. String gPLink = Convert.ToString(AdSOM.Members["gPLink"].Value);
  1170. String GPOName = null;
  1171.  
  1172. Depth = (Convert.ToString(AdSOM.Members["DistinguishedName"].Value).Split(new string[] { "OU=" }, StringSplitOptions.None)).Length -1;
  1173. if (AdSOM.Members["gPOptions"].Value != null && (int) AdSOM.Members["gPOptions"].Value == 1)
  1174. {
  1175. BlockInheritance = true;
  1176. }
  1177. var GPLinks = gPLink.Split(']', '[').Where(x => x.StartsWith("LDAP"));
  1178. int Order = (GPLinks.ToArray()).Length;
  1179. if (Order == 0)
  1180. {
  1181. PSObject SOMObj = new PSObject();
  1182. SOMObj.Members.Add(new PSNoteProperty("Name", AdSOM.Members["Name"].Value));
  1183. SOMObj.Members.Add(new PSNoteProperty("Depth", Depth));
  1184. SOMObj.Members.Add(new PSNoteProperty("DistinguishedName", AdSOM.Members["DistinguishedName"].Value));
  1185. SOMObj.Members.Add(new PSNoteProperty("Link Order", null));
  1186. SOMObj.Members.Add(new PSNoteProperty("GPO", GPOName));
  1187. SOMObj.Members.Add(new PSNoteProperty("Enforced", Enforced));
  1188. SOMObj.Members.Add(new PSNoteProperty("Link Enabled", LinkEnabled));
  1189. SOMObj.Members.Add(new PSNoteProperty("BlockInheritance", BlockInheritance));
  1190. SOMObj.Members.Add(new PSNoteProperty("gPLink", gPLink));
  1191. SOMObj.Members.Add(new PSNoteProperty("gPOptions", AdSOM.Members["gPOptions"].Value));
  1192. SOMsList.Add( SOMObj );
  1193. }
  1194. foreach (String link in GPLinks)
  1195. {
  1196. String[] linksplit = link.Split('/', ';');
  1197. if (!Convert.ToBoolean((Convert.ToInt32(linksplit[3]) & 1)))
  1198. {
  1199. LinkEnabled = true;
  1200. }
  1201. else
  1202. {
  1203. LinkEnabled = false;
  1204. }
  1205. if (Convert.ToBoolean((Convert.ToInt32(linksplit[3]) & 2)))
  1206. {
  1207. Enforced = true;
  1208. }
  1209. else
  1210. {
  1211. Enforced = false;
  1212. }
  1213. GPOName = ADWSClass.AdGPODictionary.ContainsKey(linksplit[2].ToUpper()) ? ADWSClass.AdGPODictionary[linksplit[2].ToUpper()] : linksplit[2].Split('=',',')[1];
  1214. PSObject SOMObj = new PSObject();
  1215. SOMObj.Members.Add(new PSNoteProperty("Name", AdSOM.Members["Name"].Value));
  1216. SOMObj.Members.Add(new PSNoteProperty("Depth", Depth));
  1217. SOMObj.Members.Add(new PSNoteProperty("DistinguishedName", AdSOM.Members["DistinguishedName"].Value));
  1218. SOMObj.Members.Add(new PSNoteProperty("Link Order", Order));
  1219. SOMObj.Members.Add(new PSNoteProperty("GPO", GPOName));
  1220. SOMObj.Members.Add(new PSNoteProperty("Enforced", Enforced));
  1221. SOMObj.Members.Add(new PSNoteProperty("Link Enabled", LinkEnabled));
  1222. SOMObj.Members.Add(new PSNoteProperty("BlockInheritance", BlockInheritance));
  1223. SOMObj.Members.Add(new PSNoteProperty("gPLink", gPLink));
  1224. SOMObj.Members.Add(new PSNoteProperty("gPOptions", AdSOM.Members["gPOptions"].Value));
  1225. SOMsList.Add( SOMObj );
  1226. Order--;
  1227. }
  1228. return SOMsList.ToArray();
  1229. }
  1230. catch (Exception e)
  1231. {
  1232. Console.WriteLine("{0} Exception caught.", e);
  1233. return new PSObject[] { };
  1234. }
  1235. }
  1236. }
  1237.  
  1238. class PrinterRecordProcessor : IRecordProcessor
  1239. {
  1240. public PSObject[] processRecord(Object record)
  1241. {
  1242. try
  1243. {
  1244. PSObject AdPrinter = (PSObject) record;
  1245.  
  1246. PSObject PrinterObj = new PSObject();
  1247. PrinterObj.Members.Add(new PSNoteProperty("Name", AdPrinter.Members["Name"].Value));
  1248. PrinterObj.Members.Add(new PSNoteProperty("ServerName", AdPrinter.Members["serverName"].Value));
  1249. PrinterObj.Members.Add(new PSNoteProperty("ShareName", ((Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) (AdPrinter.Members["printShareName"].Value)).Value));
  1250. PrinterObj.Members.Add(new PSNoteProperty("DriverName", AdPrinter.Members["driverName"].Value));
  1251. PrinterObj.Members.Add(new PSNoteProperty("DriverVersion", AdPrinter.Members["driverVersion"].Value));
  1252. PrinterObj.Members.Add(new PSNoteProperty("PortName", ((Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) (AdPrinter.Members["portName"].Value)).Value));
  1253. PrinterObj.Members.Add(new PSNoteProperty("URL", ((Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) (AdPrinter.Members["url"].Value)).Value));
  1254. PrinterObj.Members.Add(new PSNoteProperty("whenCreated", AdPrinter.Members["whenCreated"].Value));
  1255. PrinterObj.Members.Add(new PSNoteProperty("whenChanged", AdPrinter.Members["whenChanged"].Value));
  1256. return new PSObject[] { PrinterObj };
  1257. }
  1258. catch (Exception e)
  1259. {
  1260. Console.WriteLine("{0} Exception caught.", e);
  1261. return new PSObject[] { };
  1262. }
  1263. }
  1264. }
  1265.  
  1266. class ComputerRecordProcessor : IRecordProcessor
  1267. {
  1268. public PSObject[] processRecord(Object record)
  1269. {
  1270. try
  1271. {
  1272. PSObject AdComputer = (PSObject) record;
  1273. int? DaysSinceLastLogon = null;
  1274. int? DaysSinceLastPasswordChange = null;
  1275. bool Dormant = false;
  1276. bool PasswordNotChangedafterMaxAge = false;
  1277. String SIDHistory = "";
  1278. String DelegationType = null;
  1279. String DelegationProtocol = null;
  1280. String DelegationServices = null;
  1281. DateTime? LastLogonDate = null;
  1282. DateTime? PasswordLastSet = null;
  1283.  
  1284. if (AdComputer.Members["LastLogonDate"].Value != null)
  1285. {
  1286. //LastLogonDate = DateTime.FromFileTime((long)(AdComputer.Members["lastLogonTimeStamp"].Value));
  1287. // LastLogonDate is lastLogonTimeStamp converted to local time
  1288. LastLogonDate = Convert.ToDateTime(AdComputer.Members["LastLogonDate"].Value);
  1289. DaysSinceLastLogon = Math.Abs((Date1 - (DateTime)LastLogonDate).Days);
  1290. if (DaysSinceLastLogon > DormantTimeSpan)
  1291. {
  1292. Dormant = true;
  1293. }
  1294. }
  1295. if (AdComputer.Members["PasswordLastSet"].Value != null)
  1296. {
  1297. //PasswordLastSet = DateTime.FromFileTime((long)(AdComputer.Members["pwdLastSet"].Value));
  1298. // PasswordLastSet is pwdLastSet converted to local time
  1299. PasswordLastSet = Convert.ToDateTime(AdComputer.Members["PasswordLastSet"].Value);
  1300. DaysSinceLastPasswordChange = Math.Abs((Date1 - (DateTime)PasswordLastSet).Days);
  1301. if (DaysSinceLastPasswordChange > PassMaxAge)
  1302. {
  1303. PasswordNotChangedafterMaxAge = true;
  1304. }
  1305. }
  1306. if ( ((bool) AdComputer.Members["TrustedForDelegation"].Value) && ((int) AdComputer.Members["primaryGroupID"].Value == 515) )
  1307. {
  1308. DelegationType = "Unconstrained";
  1309. DelegationServices = "Any";
  1310. }
  1311. if (AdComputer.Members["msDS-AllowedToDelegateTo"] != null)
  1312. {
  1313. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection delegateto = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) AdComputer.Members["msDS-AllowedToDelegateTo"].Value;
  1314. if (delegateto.Value != null)
  1315. {
  1316. DelegationType = "Constrained";
  1317. if (delegateto.Value is System.String[])
  1318. {
  1319. foreach (var value in (String[]) delegateto.Value)
  1320. {
  1321. DelegationServices = DelegationServices + "," + Convert.ToString(value);
  1322. }
  1323. DelegationServices = DelegationServices.TrimStart(',');
  1324. }
  1325. else
  1326. {
  1327. DelegationServices = Convert.ToString(delegateto.Value);
  1328. }
  1329. }
  1330. }
  1331. if ((bool) AdComputer.Members["TrustedToAuthForDelegation"].Value)
  1332. {
  1333. DelegationProtocol = "Any";
  1334. }
  1335. else if (DelegationType != null)
  1336. {
  1337. DelegationProtocol = "Kerberos";
  1338. }
  1339. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection history = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection) AdComputer.Members["SIDHistory"].Value;
  1340. if (history.Value is System.Security.Principal.SecurityIdentifier[])
  1341. {
  1342. string sids = "";
  1343. foreach (var value in (SecurityIdentifier[]) history.Value)
  1344. {
  1345. sids = sids + "," + Convert.ToString(value);
  1346. }
  1347. SIDHistory = sids.TrimStart(',');
  1348. }
  1349. else
  1350. {
  1351. SIDHistory = history != null ? Convert.ToString(history.Value) : "";
  1352. }
  1353. String OperatingSystem = CleanString((AdComputer.Members["OperatingSystem"].Value != null ? AdComputer.Members["OperatingSystem"].Value : "-") + " " + AdComputer.Members["OperatingSystemHotfix"].Value + " " + AdComputer.Members["OperatingSystemServicePack"].Value + " " + AdComputer.Members["OperatingSystemVersion"].Value);
  1354.  
  1355. PSObject ComputerObj = new PSObject();
  1356. ComputerObj.Members.Add(new PSNoteProperty("Name", AdComputer.Members["Name"].Value));
  1357. ComputerObj.Members.Add(new PSNoteProperty("DNSHostName", AdComputer.Members["DNSHostName"].Value));
  1358. ComputerObj.Members.Add(new PSNoteProperty("Enabled", AdComputer.Members["Enabled"].Value));
  1359. ComputerObj.Members.Add(new PSNoteProperty("IPv4Address", AdComputer.Members["IPv4Address"].Value));
  1360. ComputerObj.Members.Add(new PSNoteProperty("Operating System", OperatingSystem));
  1361. ComputerObj.Members.Add(new PSNoteProperty("Logon Age (days)", DaysSinceLastLogon));
  1362. ComputerObj.Members.Add(new PSNoteProperty("Password Age (days)", DaysSinceLastPasswordChange));
  1363. ComputerObj.Members.Add(new PSNoteProperty("Dormant (> " + DormantTimeSpan + " days)", Dormant));
  1364. ComputerObj.Members.Add(new PSNoteProperty("Password Age (> " + PassMaxAge + " days)", PasswordNotChangedafterMaxAge));
  1365. ComputerObj.Members.Add(new PSNoteProperty("Delegation Type", DelegationType));
  1366. ComputerObj.Members.Add(new PSNoteProperty("Delegation Protocol", DelegationProtocol));
  1367. ComputerObj.Members.Add(new PSNoteProperty("Delegation Services", DelegationServices));
  1368. ComputerObj.Members.Add(new PSNoteProperty("UserName", AdComputer.Members["SamAccountName"].Value));
  1369. ComputerObj.Members.Add(new PSNoteProperty("Primary Group ID", AdComputer.Members["primaryGroupID"].Value));
  1370. ComputerObj.Members.Add(new PSNoteProperty("SID", AdComputer.Members["SID"].Value));
  1371. ComputerObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  1372. ComputerObj.Members.Add(new PSNoteProperty("Description", AdComputer.Members["Description"].Value));
  1373. ComputerObj.Members.Add(new PSNoteProperty("ms-ds-CreatorSid", AdComputer.Members["ms-ds-CreatorSid"].Value));
  1374. ComputerObj.Members.Add(new PSNoteProperty("Last Logon Date", LastLogonDate));
  1375. ComputerObj.Members.Add(new PSNoteProperty("Password LastSet", PasswordLastSet));
  1376. ComputerObj.Members.Add(new PSNoteProperty("UserAccountControl", AdComputer.Members["UserAccountControl"].Value));
  1377. ComputerObj.Members.Add(new PSNoteProperty("whenCreated", AdComputer.Members["whenCreated"].Value));
  1378. ComputerObj.Members.Add(new PSNoteProperty("whenChanged", AdComputer.Members["whenChanged"].Value));
  1379. ComputerObj.Members.Add(new PSNoteProperty("Distinguished Name", AdComputer.Members["DistinguishedName"].Value));
  1380. return new PSObject[] { ComputerObj };
  1381. }
  1382. catch (Exception e)
  1383. {
  1384. Console.WriteLine("{0} Exception caught.", e);
  1385. return new PSObject[] { };
  1386. }
  1387. }
  1388. }
  1389.  
  1390. class ComputerSPNRecordProcessor : IRecordProcessor
  1391. {
  1392. public PSObject[] processRecord(Object record)
  1393. {
  1394. try
  1395. {
  1396. PSObject AdComputer = (PSObject) record;
  1397. List<PSObject> SPNList = new List<PSObject>();
  1398.  
  1399. Microsoft.ActiveDirectory.Management.ADPropertyValueCollection SPNs = (Microsoft.ActiveDirectory.Management.ADPropertyValueCollection)AdComputer.Members["servicePrincipalName"].Value;
  1400. if (SPNs.Value is System.String[])
  1401. {
  1402. foreach (String SPN in (System.String[])SPNs.Value)
  1403. {
  1404. bool flag = true;
  1405. String[] SPNArray = SPN.Split('/');
  1406. foreach (PSObject Obj in SPNList)
  1407. {
  1408. if ( (String) Obj.Members["Service"].Value == SPNArray[0] )
  1409. {
  1410. Obj.Members["Host"].Value = String.Join(",", (Obj.Members["Host"].Value + "," + SPNArray[1]).Split(',').Distinct().ToArray());
  1411. flag = false;
  1412. }
  1413. }
  1414. if (flag)
  1415. {
  1416. PSObject ComputerSPNObj = new PSObject();
  1417. ComputerSPNObj.Members.Add(new PSNoteProperty("Name", AdComputer.Members["Name"].Value));
  1418. ComputerSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  1419. ComputerSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  1420. SPNList.Add( ComputerSPNObj );
  1421. }
  1422. }
  1423. }
  1424. else
  1425. {
  1426. String[] SPNArray = Convert.ToString(SPNs.Value).Split('/');
  1427. PSObject ComputerSPNObj = new PSObject();
  1428. ComputerSPNObj.Members.Add(new PSNoteProperty("Name", AdComputer.Members["Name"].Value));
  1429. ComputerSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  1430. ComputerSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  1431. SPNList.Add( ComputerSPNObj );
  1432. }
  1433. return SPNList.ToArray();
  1434. }
  1435. catch (Exception e)
  1436. {
  1437. Console.WriteLine("{0} Exception caught.", e);
  1438. return new PSObject[] { };
  1439. }
  1440. }
  1441. }
  1442.  
  1443. class LAPSRecordProcessor : IRecordProcessor
  1444. {
  1445. public PSObject[] processRecord(Object record)
  1446. {
  1447. try
  1448. {
  1449. PSObject AdComputer = (PSObject) record;
  1450. bool PasswordStored = false;
  1451. DateTime? CurrentExpiration = null;
  1452. try
  1453. {
  1454. CurrentExpiration = DateTime.FromFileTime((long)(AdComputer.Members["ms-Mcs-AdmPwdExpirationTime"].Value));
  1455. PasswordStored = true;
  1456. }
  1457. catch //(Exception e)
  1458. {
  1459. //Console.WriteLine("{0} Exception caught.", e);
  1460. }
  1461. PSObject LAPSObj = new PSObject();
  1462. LAPSObj.Members.Add(new PSNoteProperty("Hostname", (AdComputer.Members["DNSHostName"].Value != null ? AdComputer.Members["DNSHostName"].Value : AdComputer.Members["CN"].Value )));
  1463. LAPSObj.Members.Add(new PSNoteProperty("Stored", PasswordStored));
  1464. LAPSObj.Members.Add(new PSNoteProperty("Readable", (AdComputer.Members["ms-Mcs-AdmPwd"].Value != null ? true : false)));
  1465. LAPSObj.Members.Add(new PSNoteProperty("Password", AdComputer.Members["ms-Mcs-AdmPwd"].Value));
  1466. LAPSObj.Members.Add(new PSNoteProperty("Expiration", CurrentExpiration));
  1467. return new PSObject[] { LAPSObj };
  1468. }
  1469. catch (Exception e)
  1470. {
  1471. Console.WriteLine("{0} Exception caught.", e);
  1472. return new PSObject[] { };
  1473. }
  1474. }
  1475. }
  1476.  
  1477. class SIDRecordDictionaryProcessor : IRecordProcessor
  1478. {
  1479. public PSObject[] processRecord(Object record)
  1480. {
  1481. try
  1482. {
  1483. PSObject AdObject = (PSObject) record;
  1484. switch (Convert.ToString(AdObject.Members["ObjectClass"].Value))
  1485. {
  1486. case "user":
  1487. case "computer":
  1488. case "group":
  1489. ADWSClass.AdSIDDictionary.Add(Convert.ToString(AdObject.Members["objectsid"].Value), Convert.ToString(AdObject.Members["Name"].Value));
  1490. break;
  1491. }
  1492. return new PSObject[] { };
  1493. }
  1494. catch (Exception e)
  1495. {
  1496. Console.WriteLine("{0} {1} Exception caught.", ((PSObject) record).Members["ObjectClass"].Value, e);
  1497. return new PSObject[] { };
  1498. }
  1499. }
  1500. }
  1501.  
  1502. class DACLRecordProcessor : IRecordProcessor
  1503. {
  1504. public PSObject[] processRecord(Object record)
  1505. {
  1506. try
  1507. {
  1508. PSObject AdObject = (PSObject) record;
  1509. String Name = null;
  1510. String Type = null;
  1511. List<PSObject> DACLList = new List<PSObject>();
  1512.  
  1513. Name = Convert.ToString(AdObject.Members["Name"].Value);
  1514.  
  1515. switch (Convert.ToString(AdObject.Members["objectClass"].Value))
  1516. {
  1517. case "user":
  1518. Type = "User";
  1519. break;
  1520. case "computer":
  1521. Type = "Computer";
  1522. break;
  1523. case "group":
  1524. Type = "Group";
  1525. break;
  1526. case "container":
  1527. Type = "Container";
  1528. break;
  1529. case "groupPolicyContainer":
  1530. Type = "GPO";
  1531. Name = Convert.ToString(AdObject.Members["DisplayName"].Value);
  1532. break;
  1533. case "organizationalUnit":
  1534. Type = "OU";
  1535. break;
  1536. case "domainDNS":
  1537. Type = "Domain";
  1538. break;
  1539. default:
  1540. Type = Convert.ToString(AdObject.Members["objectClass"].Value);
  1541. break;
  1542. }
  1543.  
  1544. // When the user is not allowed to query the ntsecuritydescriptor attribute.
  1545. if (AdObject.Members["ntsecuritydescriptor"] != null)
  1546. {
  1547. DirectoryObjectSecurity DirObjSec = (DirectoryObjectSecurity) AdObject.Members["ntsecuritydescriptor"].Value;
  1548. AuthorizationRuleCollection AccessRules = (AuthorizationRuleCollection) DirObjSec.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount));
  1549. foreach (ActiveDirectoryAccessRule Rule in AccessRules)
  1550. {
  1551. String IdentityReference = Convert.ToString(Rule.IdentityReference);
  1552. String Owner = Convert.ToString(DirObjSec.GetOwner(typeof(System.Security.Principal.SecurityIdentifier)));
  1553. PSObject ObjectObj = new PSObject();
  1554. ObjectObj.Members.Add(new PSNoteProperty("Name", CleanString(Name)));
  1555. ObjectObj.Members.Add(new PSNoteProperty("Type", Type));
  1556. ObjectObj.Members.Add(new PSNoteProperty("ObjectTypeName", ADWSClass.GUIDs[Convert.ToString(Rule.ObjectType)]));
  1557. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectTypeName", ADWSClass.GUIDs[Convert.ToString(Rule.InheritedObjectType)]));
  1558. ObjectObj.Members.Add(new PSNoteProperty("ActiveDirectoryRights", Rule.ActiveDirectoryRights));
  1559. ObjectObj.Members.Add(new PSNoteProperty("AccessControlType", Rule.AccessControlType));
  1560. ObjectObj.Members.Add(new PSNoteProperty("IdentityReferenceName", ADWSClass.AdSIDDictionary.ContainsKey(IdentityReference) ? ADWSClass.AdSIDDictionary[IdentityReference] : IdentityReference));
  1561. ObjectObj.Members.Add(new PSNoteProperty("OwnerName", ADWSClass.AdSIDDictionary.ContainsKey(Owner) ? ADWSClass.AdSIDDictionary[Owner] : Owner));
  1562. ObjectObj.Members.Add(new PSNoteProperty("Inherited", Rule.IsInherited));
  1563. ObjectObj.Members.Add(new PSNoteProperty("ObjectFlags", Rule.ObjectFlags));
  1564. ObjectObj.Members.Add(new PSNoteProperty("InheritanceFlags", Rule.InheritanceFlags));
  1565. ObjectObj.Members.Add(new PSNoteProperty("InheritanceType", Rule.InheritanceType));
  1566. ObjectObj.Members.Add(new PSNoteProperty("PropagationFlags", Rule.PropagationFlags));
  1567. ObjectObj.Members.Add(new PSNoteProperty("ObjectType", Rule.ObjectType));
  1568. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectType", Rule.InheritedObjectType));
  1569. ObjectObj.Members.Add(new PSNoteProperty("IdentityReference", Rule.IdentityReference));
  1570. ObjectObj.Members.Add(new PSNoteProperty("Owner", Owner));
  1571. ObjectObj.Members.Add(new PSNoteProperty("DistinguishedName", AdObject.Members["DistinguishedName"].Value));
  1572. DACLList.Add( ObjectObj );
  1573. }
  1574. }
  1575.  
  1576. return DACLList.ToArray();
  1577. }
  1578. catch (Exception e)
  1579. {
  1580. Console.WriteLine("{0} Exception caught.", e);
  1581. return new PSObject[] { };
  1582. }
  1583. }
  1584. }
  1585.  
  1586. class SACLRecordProcessor : IRecordProcessor
  1587. {
  1588. public PSObject[] processRecord(Object record)
  1589. {
  1590. try
  1591. {
  1592. PSObject AdObject = (PSObject) record;
  1593. String Name = null;
  1594. String Type = null;
  1595. List<PSObject> SACLList = new List<PSObject>();
  1596.  
  1597. Name = Convert.ToString(AdObject.Members["Name"].Value);
  1598.  
  1599. switch (Convert.ToString(AdObject.Members["objectClass"].Value))
  1600. {
  1601. case "user":
  1602. Type = "User";
  1603. break;
  1604. case "computer":
  1605. Type = "Computer";
  1606. break;
  1607. case "group":
  1608. Type = "Group";
  1609. break;
  1610. case "container":
  1611. Type = "Container";
  1612. break;
  1613. case "groupPolicyContainer":
  1614. Type = "GPO";
  1615. Name = Convert.ToString(AdObject.Members["DisplayName"].Value);
  1616. break;
  1617. case "organizationalUnit":
  1618. Type = "OU";
  1619. break;
  1620. case "domainDNS":
  1621. Type = "Domain";
  1622. break;
  1623. default:
  1624. Type = Convert.ToString(AdObject.Members["objectClass"].Value);
  1625. break;
  1626. }
  1627.  
  1628. // When the user is not allowed to query the ntsecuritydescriptor attribute.
  1629. if (AdObject.Members["ntsecuritydescriptor"] != null)
  1630. {
  1631. DirectoryObjectSecurity DirObjSec = (DirectoryObjectSecurity) AdObject.Members["ntsecuritydescriptor"].Value;
  1632. AuthorizationRuleCollection AuditRules = (AuthorizationRuleCollection) DirObjSec.GetAuditRules(true,true,typeof(System.Security.Principal.NTAccount));
  1633. foreach (ActiveDirectoryAuditRule Rule in AuditRules)
  1634. {
  1635. PSObject ObjectObj = new PSObject();
  1636. ObjectObj.Members.Add(new PSNoteProperty("Name", CleanString(Name)));
  1637. ObjectObj.Members.Add(new PSNoteProperty("Type", Type));
  1638. ObjectObj.Members.Add(new PSNoteProperty("ObjectTypeName", ADWSClass.GUIDs[Convert.ToString(Rule.ObjectType)]));
  1639. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectTypeName", ADWSClass.GUIDs[Convert.ToString(Rule.InheritedObjectType)]));
  1640. ObjectObj.Members.Add(new PSNoteProperty("ActiveDirectoryRights", Rule.ActiveDirectoryRights));
  1641. ObjectObj.Members.Add(new PSNoteProperty("IdentityReference", Rule.IdentityReference));
  1642. ObjectObj.Members.Add(new PSNoteProperty("AuditFlags", Rule.AuditFlags));
  1643. ObjectObj.Members.Add(new PSNoteProperty("ObjectFlags", Rule.ObjectFlags));
  1644. ObjectObj.Members.Add(new PSNoteProperty("InheritanceFlags", Rule.InheritanceFlags));
  1645. ObjectObj.Members.Add(new PSNoteProperty("InheritanceType", Rule.InheritanceType));
  1646. ObjectObj.Members.Add(new PSNoteProperty("Inherited", Rule.IsInherited));
  1647. ObjectObj.Members.Add(new PSNoteProperty("PropagationFlags", Rule.PropagationFlags));
  1648. ObjectObj.Members.Add(new PSNoteProperty("ObjectType", Rule.ObjectType));
  1649. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectType", Rule.InheritedObjectType));
  1650. SACLList.Add( ObjectObj );
  1651. }
  1652. }
  1653.  
  1654. return SACLList.ToArray();
  1655. }
  1656. catch (Exception e)
  1657. {
  1658. Console.WriteLine("{0} Exception caught.", e);
  1659. return new PSObject[] { };
  1660. }
  1661. }
  1662. }
  1663.  
  1664. //The interface and implmentation class used to handle the results (this implementation just writes the strings to a file)
  1665.  
  1666. interface IResultsHandler
  1667. {
  1668. void processResults(Object[] t);
  1669.  
  1670. Object[] finalise();
  1671. }
  1672.  
  1673. class SimpleResultsHandler : IResultsHandler
  1674. {
  1675. private Object lockObj = new Object();
  1676. private List<Object> processed = new List<Object>();
  1677.  
  1678. public SimpleResultsHandler()
  1679. {
  1680. }
  1681.  
  1682. public void processResults(Object[] results)
  1683. {
  1684. lock (lockObj)
  1685. {
  1686. if (results.Length != 0)
  1687. {
  1688. for (var i = 0; i < results.Length; i++)
  1689. {
  1690. processed.Add((PSObject)results[i]);
  1691. }
  1692. }
  1693. }
  1694. }
  1695.  
  1696. public Object[] finalise()
  1697. {
  1698. return processed.ToArray();
  1699. }
  1700. }
  1701. }
  1702. }
  1703. "@
  1704.  
  1705. $LDAPSource = @"
  1706. // Thanks Dennis Albuquerque for the C# multithreading code
  1707. using System;
  1708. using System.Collections;
  1709. using System.Collections.Generic;
  1710. using System.Linq;
  1711. using System.Net;
  1712. using System.Threading;
  1713. using System.DirectoryServices;
  1714. using System.Security.Principal;
  1715. using System.Security.AccessControl;
  1716. using System.Management.Automation;
  1717.  
  1718. namespace ADRecon
  1719. {
  1720. public static class LDAPClass
  1721. {
  1722. private static DateTime Date1;
  1723. private static int PassMaxAge;
  1724. private static int DormantTimeSpan;
  1725. private static Dictionary<String, String> AdGroupDictionary = new Dictionary<String, String>();
  1726. private static String DomainSID;
  1727. private static Dictionary<String, String> AdGPODictionary = new Dictionary<String, String>();
  1728. private static Hashtable GUIDs = new Hashtable();
  1729. private static Dictionary<String, String> AdSIDDictionary = new Dictionary<String, String>();
  1730. private static readonly HashSet<string> Groups = new HashSet<string> ( new String[] {"268435456", "268435457", "536870912", "536870913"} );
  1731. private static readonly HashSet<string> Users = new HashSet<string> ( new String[] { "805306368" } );
  1732. private static readonly HashSet<string> Computers = new HashSet<string> ( new String[] { "805306369" }) ;
  1733. private static readonly HashSet<string> TrustAccounts = new HashSet<string> ( new String[] { "805306370" } );
  1734.  
  1735. [Flags]
  1736. //Values taken from https://support.microsoft.com/en-au/kb/305144
  1737. public enum UACFlags
  1738. {
  1739. SCRIPT = 1, // 0x1
  1740. ACCOUNTDISABLE = 2, // 0x2
  1741. HOMEDIR_REQUIRED = 8, // 0x8
  1742. LOCKOUT = 16, // 0x10
  1743. PASSWD_NOTREQD = 32, // 0x20
  1744. PASSWD_CANT_CHANGE = 64, // 0x40
  1745. ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128, // 0x80
  1746. TEMP_DUPLICATE_ACCOUNT = 256, // 0x100
  1747. NORMAL_ACCOUNT = 512, // 0x200
  1748. INTERDOMAIN_TRUST_ACCOUNT = 2048, // 0x800
  1749. WORKSTATION_TRUST_ACCOUNT = 4096, // 0x1000
  1750. SERVER_TRUST_ACCOUNT = 8192, // 0x2000
  1751. DONT_EXPIRE_PASSWD = 65536, // 0x10000
  1752. MNS_LOGON_ACCOUNT = 131072, // 0x20000
  1753. SMARTCARD_REQUIRED = 262144, // 0x40000
  1754. TRUSTED_FOR_DELEGATION = 524288, // 0x80000
  1755. NOT_DELEGATED = 1048576, // 0x100000
  1756. USE_DES_KEY_ONLY = 2097152, // 0x200000
  1757. DONT_REQUIRE_PREAUTH = 4194304, // 0x400000
  1758. PASSWORD_EXPIRED = 8388608, // 0x800000
  1759. TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216, // 0x1000000
  1760. PARTIAL_SECRETS_ACCOUNT = 67108864 // 0x04000000
  1761. }
  1762.  
  1763. [Flags]
  1764. //Values taken from https://blogs.msdn.microsoft.com/openspecification/2011/05/30/windows-configurations-for-kerberos-supported-encryption-type/
  1765. public enum KerbEncFlags
  1766. {
  1767. ZERO = 0,
  1768. DES_CBC_CRC = 1, // 0x1
  1769. DES_CBC_MD5 = 2, // 0x2
  1770. RC4_HMAC = 4, // 0x4
  1771. AES128_CTS_HMAC_SHA1_96 = 8, // 0x18
  1772. AES256_CTS_HMAC_SHA1_96 = 16 // 0x10
  1773. }
  1774.  
  1775. [Flags]
  1776. //Values taken from https://support.microsoft.com/en-au/kb/305144
  1777. public enum GroupTypeFlags
  1778. {
  1779. GLOBAL_GROUP = 2, // 0x00000002
  1780. DOMAIN_LOCAL_GROUP = 4, // 0x00000004
  1781. LOCAL_GROUP = 4, // 0x00000004
  1782. UNIVERSAL_GROUP = 8, // 0x00000008
  1783. SECURITY_ENABLED = -2147483648 // 0x80000000
  1784. }
  1785.  
  1786. private static readonly Dictionary<String, String> Replacements = new Dictionary<String, String>()
  1787. {
  1788. //{System.Environment.NewLine, ""},
  1789. //{",", ";"},
  1790. {"\"", "'"}
  1791. };
  1792.  
  1793. public static String CleanString(Object StringtoClean)
  1794. {
  1795. // Remove extra spaces and new lines
  1796. String CleanedString = String.Join(" ", ((Convert.ToString(StringtoClean)).Split((string[]) null, StringSplitOptions.RemoveEmptyEntries)));
  1797. foreach (String Replacement in Replacements.Keys)
  1798. {
  1799. CleanedString = CleanedString.Replace(Replacement, Replacements[Replacement]);
  1800. }
  1801. return CleanedString;
  1802. }
  1803.  
  1804. public static int ObjectCount(Object[] ADRObject)
  1805. {
  1806. return ADRObject.Length;
  1807. }
  1808.  
  1809. public static bool LAPSCheck(Object[] AdComputers)
  1810. {
  1811. bool LAPS = false;
  1812. foreach (SearchResult AdComputer in AdComputers)
  1813. {
  1814. if (AdComputer.Properties["ms-mcs-admpwdexpirationtime"].Count == 1)
  1815. {
  1816. LAPS = true;
  1817. return LAPS;
  1818. }
  1819. }
  1820. return LAPS;
  1821. }
  1822.  
  1823. public static Object[] UserParser(Object[] AdUsers, DateTime Date1, int DormantTimeSpan, int PassMaxAge, int numOfThreads)
  1824. {
  1825. LDAPClass.Date1 = Date1;
  1826. LDAPClass.DormantTimeSpan = DormantTimeSpan;
  1827. LDAPClass.PassMaxAge = PassMaxAge;
  1828.  
  1829. Object[] ADRObj = runProcessor(AdUsers, numOfThreads, "Users");
  1830. return ADRObj;
  1831. }
  1832.  
  1833. public static Object[] UserSPNParser(Object[] AdUsers, int numOfThreads)
  1834. {
  1835. Object[] ADRObj = runProcessor(AdUsers, numOfThreads, "UserSPNs");
  1836. return ADRObj;
  1837. }
  1838.  
  1839. public static Object[] GroupParser(Object[] AdGroups, int numOfThreads)
  1840. {
  1841. Object[] ADRObj = runProcessor(AdGroups, numOfThreads, "Groups");
  1842. return ADRObj;
  1843. }
  1844.  
  1845. public static Object[] GroupMemberParser(Object[] AdGroups, Object[] AdGroupMembers, String DomainSID, int numOfThreads)
  1846. {
  1847. LDAPClass.AdGroupDictionary = new Dictionary<String, String>();
  1848. runProcessor(AdGroups, numOfThreads, "GroupsDictionary");
  1849. LDAPClass.DomainSID = DomainSID;
  1850. Object[] ADRObj = runProcessor(AdGroupMembers, numOfThreads, "GroupMembers");
  1851. return ADRObj;
  1852. }
  1853.  
  1854. public static Object[] OUParser(Object[] AdOUs, int numOfThreads)
  1855. {
  1856. Object[] ADRObj = runProcessor(AdOUs, numOfThreads, "OUs");
  1857. return ADRObj;
  1858. }
  1859.  
  1860. public static Object[] GPOParser(Object[] AdGPOs, int numOfThreads)
  1861. {
  1862. Object[] ADRObj = runProcessor(AdGPOs, numOfThreads, "GPOs");
  1863. return ADRObj;
  1864. }
  1865.  
  1866. public static Object[] SOMParser(Object[] AdGPOs, Object[] AdSOMs, int numOfThreads)
  1867. {
  1868. LDAPClass.AdGPODictionary = new Dictionary<String, String>();
  1869. runProcessor(AdGPOs, numOfThreads, "GPOsDictionary");
  1870. Object[] ADRObj = runProcessor(AdSOMs, numOfThreads, "SOMs");
  1871. return ADRObj;
  1872. }
  1873.  
  1874. public static Object[] PrinterParser(Object[] ADPrinters, int numOfThreads)
  1875. {
  1876. Object[] ADRObj = runProcessor(ADPrinters, numOfThreads, "Printers");
  1877. return ADRObj;
  1878. }
  1879.  
  1880. public static Object[] ComputerParser(Object[] AdComputers, DateTime Date1, int DormantTimeSpan, int PassMaxAge, int numOfThreads)
  1881. {
  1882. LDAPClass.Date1 = Date1;
  1883. LDAPClass.DormantTimeSpan = DormantTimeSpan;
  1884. LDAPClass.PassMaxAge = PassMaxAge;
  1885.  
  1886. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "Computers");
  1887. return ADRObj;
  1888. }
  1889.  
  1890. public static Object[] ComputerSPNParser(Object[] AdComputers, int numOfThreads)
  1891. {
  1892. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "ComputerSPNs");
  1893. return ADRObj;
  1894. }
  1895.  
  1896. public static Object[] LAPSParser(Object[] AdComputers, int numOfThreads)
  1897. {
  1898. Object[] ADRObj = runProcessor(AdComputers, numOfThreads, "LAPS");
  1899. return ADRObj;
  1900. }
  1901.  
  1902. public static Object[] DACLParser(Object[] ADObjects, Object PSGUIDs, int numOfThreads)
  1903. {
  1904. LDAPClass.AdSIDDictionary = new Dictionary<String, String>();
  1905. runProcessor(ADObjects, numOfThreads, "SIDDictionary");
  1906. LDAPClass.GUIDs = (Hashtable) PSGUIDs;
  1907. Object[] ADRObj = runProcessor(ADObjects, numOfThreads, "DACLs");
  1908. return ADRObj;
  1909. }
  1910.  
  1911. public static Object[] SACLParser(Object[] ADObjects, Object PSGUIDs, int numOfThreads)
  1912. {
  1913. LDAPClass.GUIDs = (Hashtable) PSGUIDs;
  1914. Object[] ADRObj = runProcessor(ADObjects, numOfThreads, "SACLs");
  1915. return ADRObj;
  1916. }
  1917.  
  1918. static Object[] runProcessor(Object[] arrayToProcess, int numOfThreads, string processorType)
  1919. {
  1920. int totalRecords = arrayToProcess.Length;
  1921. IRecordProcessor recordProcessor = recordProcessorFactory(processorType);
  1922. IResultsHandler resultsHandler = new SimpleResultsHandler ();
  1923. int numberOfRecordsPerThread = totalRecords / numOfThreads;
  1924. int remainders = totalRecords % numOfThreads;
  1925.  
  1926. Thread[] threads = new Thread[numOfThreads];
  1927. for (int i = 0; i < numOfThreads; i++)
  1928. {
  1929. int numberOfRecordsToProcess = numberOfRecordsPerThread;
  1930. if (i == (numOfThreads - 1))
  1931. {
  1932. //last thread, do the remaining records
  1933. numberOfRecordsToProcess += remainders;
  1934. }
  1935.  
  1936. //split the full array into chunks to be given to different threads
  1937. Object[] sliceToProcess = new Object[numberOfRecordsToProcess];
  1938. Array.Copy(arrayToProcess, i * numberOfRecordsPerThread, sliceToProcess, 0, numberOfRecordsToProcess);
  1939. ProcessorThread processorThread = new ProcessorThread(i, recordProcessor, resultsHandler, sliceToProcess);
  1940. threads[i] = new Thread(processorThread.processThreadRecords);
  1941. threads[i].Start();
  1942. }
  1943. foreach (Thread t in threads)
  1944. {
  1945. t.Join();
  1946. }
  1947.  
  1948. return resultsHandler.finalise();
  1949. }
  1950.  
  1951. static IRecordProcessor recordProcessorFactory(String name)
  1952. {
  1953. switch (name)
  1954. {
  1955. case "Users":
  1956. return new UserRecordProcessor();
  1957. case "UserSPNs":
  1958. return new UserSPNRecordProcessor();
  1959. case "Groups":
  1960. return new GroupRecordProcessor();
  1961. case "GroupsDictionary":
  1962. return new GroupRecordDictionaryProcessor();
  1963. case "GroupMembers":
  1964. return new GroupMemberRecordProcessor();
  1965. case "OUs":
  1966. return new OURecordProcessor();
  1967. case "GPOs":
  1968. return new GPORecordProcessor();
  1969. case "GPOsDictionary":
  1970. return new GPORecordDictionaryProcessor();
  1971. case "SOMs":
  1972. return new SOMRecordProcessor();
  1973. case "Printers":
  1974. return new PrinterRecordProcessor();
  1975. case "Computers":
  1976. return new ComputerRecordProcessor();
  1977. case "ComputerSPNs":
  1978. return new ComputerSPNRecordProcessor();
  1979. case "LAPS":
  1980. return new LAPSRecordProcessor();
  1981. case "SIDDictionary":
  1982. return new SIDRecordDictionaryProcessor();
  1983. case "DACLs":
  1984. return new DACLRecordProcessor();
  1985. case "SACLs":
  1986. return new SACLRecordProcessor();
  1987. }
  1988. throw new ArgumentException("Invalid processor type " + name);
  1989. }
  1990.  
  1991. class ProcessorThread
  1992. {
  1993. readonly int id;
  1994. readonly IRecordProcessor recordProcessor;
  1995. readonly IResultsHandler resultsHandler;
  1996. readonly Object[] objectsToBeProcessed;
  1997.  
  1998. public ProcessorThread(int id, IRecordProcessor recordProcessor, IResultsHandler resultsHandler, Object[] objectsToBeProcessed)
  1999. {
  2000. this.recordProcessor = recordProcessor;
  2001. this.id = id;
  2002. this.resultsHandler = resultsHandler;
  2003. this.objectsToBeProcessed = objectsToBeProcessed;
  2004. }
  2005.  
  2006. public void processThreadRecords()
  2007. {
  2008. for (int i = 0; i < objectsToBeProcessed.Length; i++)
  2009. {
  2010. Object[] result = recordProcessor.processRecord(objectsToBeProcessed[i]);
  2011. resultsHandler.processResults(result); //this is a thread safe operation
  2012. }
  2013. }
  2014. }
  2015.  
  2016. //The interface and implmentation class used to process a record (this implemmentation just returns a log type string)
  2017.  
  2018. interface IRecordProcessor
  2019. {
  2020. PSObject[] processRecord(Object record);
  2021. }
  2022.  
  2023. class UserRecordProcessor : IRecordProcessor
  2024. {
  2025. public PSObject[] processRecord(Object record)
  2026. {
  2027. try
  2028. {
  2029. SearchResult AdUser = (SearchResult) record;
  2030. bool? Enabled = null;
  2031. bool? CannotChangePassword = null;
  2032. bool? PasswordNeverExpires = null;
  2033. bool? AccountLockedOut = null;
  2034. bool? PasswordExpired = null;
  2035. bool? ReversiblePasswordEncryption = null;
  2036. bool? DelegationPermitted = null;
  2037. bool? SmartcardRequired = null;
  2038. bool? UseDESKeyOnly = null;
  2039. bool? PasswordNotRequired = null;
  2040. bool? TrustedforDelegation = null;
  2041. bool? TrustedtoAuthforDelegation = null;
  2042. bool? DoesNotRequirePreAuth = null;
  2043. bool? KerberosRC4 = null;
  2044. bool? KerberosAES128 = null;
  2045. bool? KerberosAES256 = null;
  2046. String DelegationType = null;
  2047. String DelegationProtocol = null;
  2048. String DelegationServices = null;
  2049. bool MustChangePasswordatLogon = false;
  2050. int? DaysSinceLastLogon = null;
  2051. int? DaysSinceLastPasswordChange = null;
  2052. int? AccountExpirationNumofDays = null;
  2053. bool PasswordNotChangedafterMaxAge = false;
  2054. bool NeverLoggedIn = false;
  2055. bool Dormant = false;
  2056. DateTime? LastLogonDate = null;
  2057. DateTime? PasswordLastSet = null;
  2058. DateTime? AccountExpires = null;
  2059. byte[] ntSecurityDescriptor = null;
  2060. bool DenyEveryone = false;
  2061. bool DenySelf = false;
  2062. String SIDHistory = "";
  2063.  
  2064. // When the user is not allowed to query the UserAccountControl attribute.
  2065. if (AdUser.Properties["useraccountcontrol"].Count != 0)
  2066. {
  2067. var userFlags = (UACFlags) AdUser.Properties["useraccountcontrol"][0];
  2068. Enabled = !((userFlags & UACFlags.ACCOUNTDISABLE) == UACFlags.ACCOUNTDISABLE);
  2069. PasswordNeverExpires = (userFlags & UACFlags.DONT_EXPIRE_PASSWD) == UACFlags.DONT_EXPIRE_PASSWD;
  2070. AccountLockedOut = (userFlags & UACFlags.LOCKOUT) == UACFlags.LOCKOUT;
  2071. DelegationPermitted = !((userFlags & UACFlags.NOT_DELEGATED) == UACFlags.NOT_DELEGATED);
  2072. SmartcardRequired = (userFlags & UACFlags.SMARTCARD_REQUIRED) == UACFlags.SMARTCARD_REQUIRED;
  2073. ReversiblePasswordEncryption = (userFlags & UACFlags.ENCRYPTED_TEXT_PASSWORD_ALLOWED) == UACFlags.ENCRYPTED_TEXT_PASSWORD_ALLOWED;
  2074. UseDESKeyOnly = (userFlags & UACFlags.USE_DES_KEY_ONLY) == UACFlags.USE_DES_KEY_ONLY;
  2075. PasswordNotRequired = (userFlags & UACFlags.PASSWD_NOTREQD) == UACFlags.PASSWD_NOTREQD;
  2076. PasswordExpired = (userFlags & UACFlags.PASSWORD_EXPIRED) == UACFlags.PASSWORD_EXPIRED;
  2077. TrustedforDelegation = (userFlags & UACFlags.TRUSTED_FOR_DELEGATION) == UACFlags.TRUSTED_FOR_DELEGATION;
  2078. TrustedtoAuthforDelegation = (userFlags & UACFlags.TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) == UACFlags.TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION;
  2079. DoesNotRequirePreAuth = (userFlags & UACFlags.DONT_REQUIRE_PREAUTH) == UACFlags.DONT_REQUIRE_PREAUTH;
  2080. }
  2081. if (AdUser.Properties["msds-supportedencryptiontypes"].Count != 0)
  2082. {
  2083. var userKerbEncFlags = (KerbEncFlags) AdUser.Properties["msds-supportedencryptiontypes"][0];
  2084. if (userKerbEncFlags != KerbEncFlags.ZERO)
  2085. {
  2086. KerberosRC4 = (userKerbEncFlags & KerbEncFlags.RC4_HMAC) == KerbEncFlags.RC4_HMAC;
  2087. KerberosAES128 = (userKerbEncFlags & KerbEncFlags.AES128_CTS_HMAC_SHA1_96) == KerbEncFlags.AES128_CTS_HMAC_SHA1_96;
  2088. KerberosAES256 = (userKerbEncFlags & KerbEncFlags.AES256_CTS_HMAC_SHA1_96) == KerbEncFlags.AES256_CTS_HMAC_SHA1_96;
  2089. }
  2090. }
  2091. // When the user is not allowed to query the ntsecuritydescriptor attribute.
  2092. if (AdUser.Properties["ntsecuritydescriptor"].Count != 0)
  2093. {
  2094. ntSecurityDescriptor = (byte[]) AdUser.Properties["ntsecuritydescriptor"][0];
  2095. }
  2096. else
  2097. {
  2098. DirectoryEntry AdUserEntry = ((SearchResult)record).GetDirectoryEntry();
  2099. ntSecurityDescriptor = (byte[]) AdUserEntry.ObjectSecurity.GetSecurityDescriptorBinaryForm();
  2100. }
  2101. if (ntSecurityDescriptor != null)
  2102. {
  2103. DirectoryObjectSecurity DirObjSec = new ActiveDirectorySecurity();
  2104. DirObjSec.SetSecurityDescriptorBinaryForm(ntSecurityDescriptor);
  2105. AuthorizationRuleCollection AccessRules = (AuthorizationRuleCollection) DirObjSec.GetAccessRules(true,false,typeof(System.Security.Principal.NTAccount));
  2106. foreach (ActiveDirectoryAccessRule Rule in AccessRules)
  2107. {
  2108. if ((Convert.ToString(Rule.ObjectType)).Equals("ab721a53-1e2f-11d0-9819-00aa0040529b"))
  2109. {
  2110. if (Rule.AccessControlType.ToString() == "Deny")
  2111. {
  2112. String ObjectName = Convert.ToString(Rule.IdentityReference);
  2113. if (ObjectName == "Everyone")
  2114. {
  2115. DenyEveryone = true;
  2116. }
  2117. if (ObjectName == "NT AUTHORITY\\SELF")
  2118. {
  2119. DenySelf = true;
  2120. }
  2121. }
  2122. }
  2123. }
  2124. if (DenyEveryone && DenySelf)
  2125. {
  2126. CannotChangePassword = true;
  2127. }
  2128. else
  2129. {
  2130. CannotChangePassword = false;
  2131. }
  2132. }
  2133. if (AdUser.Properties["lastlogontimestamp"].Count != 0)
  2134. {
  2135. LastLogonDate = DateTime.FromFileTime((long)(AdUser.Properties["lastlogontimestamp"][0]));
  2136. DaysSinceLastLogon = Math.Abs((Date1 - (DateTime)LastLogonDate).Days);
  2137. if (DaysSinceLastLogon > DormantTimeSpan)
  2138. {
  2139. Dormant = true;
  2140. }
  2141. }
  2142. else
  2143. {
  2144. NeverLoggedIn = true;
  2145. }
  2146. if (AdUser.Properties["pwdLastSet"].Count != 0)
  2147. {
  2148. if (Convert.ToString(AdUser.Properties["pwdlastset"][0]) == "0")
  2149. {
  2150. if ((bool) PasswordNeverExpires == false)
  2151. {
  2152. MustChangePasswordatLogon = true;
  2153. }
  2154. }
  2155. else
  2156. {
  2157. PasswordLastSet = DateTime.FromFileTime((long)(AdUser.Properties["pwdlastset"][0]));
  2158. DaysSinceLastPasswordChange = Math.Abs((Date1 - (DateTime)PasswordLastSet).Days);
  2159. if (DaysSinceLastPasswordChange > PassMaxAge)
  2160. {
  2161. PasswordNotChangedafterMaxAge = true;
  2162. }
  2163. }
  2164. }
  2165. if ((Int64) AdUser.Properties["accountExpires"][0] != (Int64) 9223372036854775807)
  2166. {
  2167. if ((Int64) AdUser.Properties["accountExpires"][0] != (Int64) 0)
  2168. {
  2169. try
  2170. {
  2171. //https://msdn.microsoft.com/en-us/library/ms675098(v=vs.85).aspx
  2172. AccountExpires = DateTime.FromFileTime((long)(AdUser.Properties["accountExpires"][0]));
  2173. AccountExpirationNumofDays = ((int)((DateTime)AccountExpires - Date1).Days);
  2174.  
  2175. }
  2176. catch //(Exception e)
  2177. {
  2178. // Console.WriteLine("{0} Exception caught.", e);
  2179. }
  2180. }
  2181. }
  2182. if ((bool) TrustedforDelegation)
  2183. {
  2184. DelegationType = "Unconstrained";
  2185. DelegationServices = "Any";
  2186. }
  2187. if (AdUser.Properties["msDS-AllowedToDelegateTo"].Count >= 1)
  2188. {
  2189. DelegationType = "Constrained";
  2190. for (int i = 0; i < AdUser.Properties["msDS-AllowedToDelegateTo"].Count; i++)
  2191. {
  2192. var delegateto = AdUser.Properties["msDS-AllowedToDelegateTo"][i];
  2193. DelegationServices = DelegationServices + "," + Convert.ToString(delegateto);
  2194. }
  2195. DelegationServices = DelegationServices.TrimStart(',');
  2196. }
  2197. if ((bool) TrustedtoAuthforDelegation)
  2198. {
  2199. DelegationProtocol = "Any";
  2200. }
  2201. else if (DelegationType != null)
  2202. {
  2203. DelegationProtocol = "Kerberos";
  2204. }
  2205. if (AdUser.Properties["sidhistory"].Count >= 1)
  2206. {
  2207. string sids = "";
  2208. for (int i = 0; i < AdUser.Properties["sidhistory"].Count; i++)
  2209. {
  2210. var history = AdUser.Properties["sidhistory"][i];
  2211. sids = sids + "," + Convert.ToString(new SecurityIdentifier((byte[])history, 0));
  2212. }
  2213. SIDHistory = sids.TrimStart(',');
  2214. }
  2215.  
  2216. PSObject UserObj = new PSObject();
  2217. UserObj.Members.Add(new PSNoteProperty("UserName", (AdUser.Properties["samaccountname"].Count != 0 ? AdUser.Properties["samaccountname"][0] : "")));
  2218. UserObj.Members.Add(new PSNoteProperty("Name", (AdUser.Properties["name"].Count != 0 ? CleanString(AdUser.Properties["name"][0]) : "")));
  2219. UserObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  2220. UserObj.Members.Add(new PSNoteProperty("Must Change Password at Logon", MustChangePasswordatLogon));
  2221. UserObj.Members.Add(new PSNoteProperty("Cannot Change Password", CannotChangePassword));
  2222. UserObj.Members.Add(new PSNoteProperty("Password Never Expires", PasswordNeverExpires));
  2223. UserObj.Members.Add(new PSNoteProperty("Reversible Password Encryption", ReversiblePasswordEncryption));
  2224. UserObj.Members.Add(new PSNoteProperty("Smartcard Logon Required", SmartcardRequired));
  2225. UserObj.Members.Add(new PSNoteProperty("Delegation Permitted", DelegationPermitted));
  2226. UserObj.Members.Add(new PSNoteProperty("Kerberos DES Only", UseDESKeyOnly));
  2227. UserObj.Members.Add(new PSNoteProperty("Kerberos RC4", KerberosRC4));
  2228. UserObj.Members.Add(new PSNoteProperty("Kerberos AES-128bit", KerberosAES128));
  2229. UserObj.Members.Add(new PSNoteProperty("Kerberos AES-256bit", KerberosAES256));
  2230. UserObj.Members.Add(new PSNoteProperty("Does Not Require Pre Auth", DoesNotRequirePreAuth));
  2231. UserObj.Members.Add(new PSNoteProperty("Never Logged in", NeverLoggedIn));
  2232. UserObj.Members.Add(new PSNoteProperty("Logon Age (days)", DaysSinceLastLogon));
  2233. UserObj.Members.Add(new PSNoteProperty("Password Age (days)", DaysSinceLastPasswordChange));
  2234. UserObj.Members.Add(new PSNoteProperty("Dormant (> " + DormantTimeSpan + " days)", Dormant));
  2235. UserObj.Members.Add(new PSNoteProperty("Password Age (> " + PassMaxAge + " days)", PasswordNotChangedafterMaxAge));
  2236. UserObj.Members.Add(new PSNoteProperty("Account Locked Out", AccountLockedOut));
  2237. UserObj.Members.Add(new PSNoteProperty("Password Expired", PasswordExpired));
  2238. UserObj.Members.Add(new PSNoteProperty("Password Not Required", PasswordNotRequired));
  2239. UserObj.Members.Add(new PSNoteProperty("Delegation Type", DelegationType));
  2240. UserObj.Members.Add(new PSNoteProperty("Delegation Protocol", DelegationProtocol));
  2241. UserObj.Members.Add(new PSNoteProperty("Delegation Services", DelegationServices));
  2242. UserObj.Members.Add(new PSNoteProperty("Logon Workstations", (AdUser.Properties["userworkstations"].Count != 0 ? AdUser.Properties["userworkstations"][0] : "")));
  2243. UserObj.Members.Add(new PSNoteProperty("AdminCount", (AdUser.Properties["admincount"].Count != 0 ? AdUser.Properties["admincount"][0] : "")));
  2244. UserObj.Members.Add(new PSNoteProperty("Primary GroupID", (AdUser.Properties["primarygroupid"].Count != 0 ? AdUser.Properties["primarygroupid"][0] : "")));
  2245. UserObj.Members.Add(new PSNoteProperty("SID", Convert.ToString(new SecurityIdentifier((byte[])AdUser.Properties["objectSID"][0], 0))));
  2246. UserObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  2247. UserObj.Members.Add(new PSNoteProperty("Description", (AdUser.Properties["Description"].Count != 0 ? CleanString(AdUser.Properties["Description"][0]) : "")));
  2248. UserObj.Members.Add(new PSNoteProperty("Title", (AdUser.Properties["Title"].Count != 0 ? CleanString(AdUser.Properties["Title"][0]) : "")));
  2249. UserObj.Members.Add(new PSNoteProperty("Department", (AdUser.Properties["Department"].Count != 0 ? CleanString(AdUser.Properties["Department"][0]) : "")));
  2250. UserObj.Members.Add(new PSNoteProperty("Company", (AdUser.Properties["Company"].Count != 0 ? CleanString(AdUser.Properties["Company"][0]) : "")));
  2251. UserObj.Members.Add(new PSNoteProperty("Manager", (AdUser.Properties["Manager"].Count != 0 ? CleanString(AdUser.Properties["Manager"][0]) : "")));
  2252. UserObj.Members.Add(new PSNoteProperty("Info", (AdUser.Properties["info"].Count != 0 ? CleanString(AdUser.Properties["info"][0]) : "")));
  2253. UserObj.Members.Add(new PSNoteProperty("Last Logon Date", LastLogonDate));
  2254. UserObj.Members.Add(new PSNoteProperty("Password LastSet", PasswordLastSet));
  2255. UserObj.Members.Add(new PSNoteProperty("Account Expiration Date", AccountExpires));
  2256. UserObj.Members.Add(new PSNoteProperty("Account Expiration (days)", AccountExpirationNumofDays));
  2257. UserObj.Members.Add(new PSNoteProperty("Mobile", (AdUser.Properties["mobile"].Count != 0 ? CleanString(AdUser.Properties["mobile"][0]) : "")));
  2258. UserObj.Members.Add(new PSNoteProperty("Email", (AdUser.Properties["mail"].Count != 0 ? CleanString(AdUser.Properties["mail"][0]) : "")));
  2259. UserObj.Members.Add(new PSNoteProperty("HomeDirectory", (AdUser.Properties["homedirectory"].Count != 0 ? AdUser.Properties["homedirectory"][0] : "")));
  2260. UserObj.Members.Add(new PSNoteProperty("ProfilePath", (AdUser.Properties["profilepath"].Count != 0 ? AdUser.Properties["profilepath"][0] : "")));
  2261. UserObj.Members.Add(new PSNoteProperty("ScriptPath", (AdUser.Properties["scriptpath"].Count != 0 ? AdUser.Properties["scriptpath"][0] : "")));
  2262. UserObj.Members.Add(new PSNoteProperty("UserAccountControl", (AdUser.Properties["useraccountcontrol"].Count != 0 ? AdUser.Properties["useraccountcontrol"][0] : "")));
  2263. UserObj.Members.Add(new PSNoteProperty("First Name", (AdUser.Properties["givenName"].Count != 0 ? CleanString(AdUser.Properties["givenName"][0]) : "")));
  2264. UserObj.Members.Add(new PSNoteProperty("Middle Name", (AdUser.Properties["middleName"].Count != 0 ? CleanString(AdUser.Properties["middleName"][0]) : "")));
  2265. UserObj.Members.Add(new PSNoteProperty("Last Name", (AdUser.Properties["sn"].Count != 0 ? CleanString(AdUser.Properties["sn"][0]) : "")));
  2266. UserObj.Members.Add(new PSNoteProperty("Country", (AdUser.Properties["c"].Count != 0 ? CleanString(AdUser.Properties["c"][0]) : "")));
  2267. UserObj.Members.Add(new PSNoteProperty("whenCreated", (AdUser.Properties["whencreated"].Count != 0 ? AdUser.Properties["whencreated"][0] : "")));
  2268. UserObj.Members.Add(new PSNoteProperty("whenChanged", (AdUser.Properties["whenchanged"].Count != 0 ? AdUser.Properties["whenchanged"][0] : "")));
  2269. UserObj.Members.Add(new PSNoteProperty("DistinguishedName", (AdUser.Properties["distinguishedname"].Count != 0 ? CleanString(AdUser.Properties["distinguishedname"][0]) : "")));
  2270. UserObj.Members.Add(new PSNoteProperty("CanonicalName", (AdUser.Properties["canonicalname"].Count != 0 ? AdUser.Properties["canonicalname"][0] : "")));
  2271. return new PSObject[] { UserObj };
  2272. }
  2273. catch (Exception e)
  2274. {
  2275. Console.WriteLine("{0} Exception caught.", e);
  2276. return new PSObject[] { };
  2277. }
  2278. }
  2279. }
  2280.  
  2281. class UserSPNRecordProcessor : IRecordProcessor
  2282. {
  2283. public PSObject[] processRecord(Object record)
  2284. {
  2285. try
  2286. {
  2287. SearchResult AdUser = (SearchResult) record;
  2288. List<PSObject> SPNList = new List<PSObject>();
  2289. bool? Enabled = null;
  2290. String Memberof = null;
  2291. DateTime? PasswordLastSet = null;
  2292.  
  2293. if (AdUser.Properties["pwdlastset"].Count != 0)
  2294. {
  2295. if (Convert.ToString(AdUser.Properties["pwdlastset"][0]) != "0")
  2296. {
  2297. PasswordLastSet = DateTime.FromFileTime((long)(AdUser.Properties["pwdLastSet"][0]));
  2298. }
  2299. }
  2300. // When the user is not allowed to query the UserAccountControl attribute.
  2301. if (AdUser.Properties["useraccountcontrol"].Count != 0)
  2302. {
  2303. var userFlags = (UACFlags) AdUser.Properties["useraccountcontrol"][0];
  2304. Enabled = !((userFlags & UACFlags.ACCOUNTDISABLE) == UACFlags.ACCOUNTDISABLE);
  2305. }
  2306. String Description = (AdUser.Properties["Description"].Count != 0 ? CleanString(AdUser.Properties["Description"][0]) : "");
  2307. String PrimaryGroupID = (AdUser.Properties["primarygroupid"].Count != 0 ? Convert.ToString(AdUser.Properties["primarygroupid"][0]) : "");
  2308. if (AdUser.Properties["memberof"].Count != 0)
  2309. {
  2310. foreach (String Member in AdUser.Properties["memberof"])
  2311. {
  2312. Memberof = Memberof + "," + ((Convert.ToString(Member)).Split(',')[0]).Split('=')[1];
  2313. }
  2314. Memberof = Memberof.TrimStart(',');
  2315. }
  2316. foreach (String SPN in AdUser.Properties["serviceprincipalname"])
  2317. {
  2318. String[] SPNArray = SPN.Split('/');
  2319. PSObject UserSPNObj = new PSObject();
  2320. UserSPNObj.Members.Add(new PSNoteProperty("Name", AdUser.Properties["name"][0]));
  2321. UserSPNObj.Members.Add(new PSNoteProperty("Username", AdUser.Properties["samaccountname"][0]));
  2322. UserSPNObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  2323. UserSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  2324. UserSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  2325. UserSPNObj.Members.Add(new PSNoteProperty("Password Last Set", PasswordLastSet));
  2326. UserSPNObj.Members.Add(new PSNoteProperty("Description", Description));
  2327. UserSPNObj.Members.Add(new PSNoteProperty("Primary GroupID", PrimaryGroupID));
  2328. UserSPNObj.Members.Add(new PSNoteProperty("Memberof", Memberof));
  2329. SPNList.Add( UserSPNObj );
  2330. }
  2331. return SPNList.ToArray();
  2332. }
  2333. catch (Exception e)
  2334. {
  2335. Console.WriteLine("{0} Exception caught.", e);
  2336. return new PSObject[] { };
  2337. }
  2338. }
  2339. }
  2340.  
  2341. class GroupRecordProcessor : IRecordProcessor
  2342. {
  2343. public PSObject[] processRecord(Object record)
  2344. {
  2345. try
  2346. {
  2347. SearchResult AdGroup = (SearchResult) record;
  2348. String ManagedByValue = AdGroup.Properties["managedby"].Count != 0 ? Convert.ToString(AdGroup.Properties["managedby"][0]) : "";
  2349. String ManagedBy = "";
  2350. String GroupCategory = null;
  2351. String GroupScope = null;
  2352. String SIDHistory = "";
  2353.  
  2354. if (AdGroup.Properties["managedBy"].Count != 0)
  2355. {
  2356. ManagedBy = (ManagedByValue.Split(',')[0]).Split('=')[1];
  2357. }
  2358.  
  2359. if (AdGroup.Properties["grouptype"].Count != 0)
  2360. {
  2361. var groupTypeFlags = (GroupTypeFlags) AdGroup.Properties["grouptype"][0];
  2362. GroupCategory = (groupTypeFlags & GroupTypeFlags.SECURITY_ENABLED) == GroupTypeFlags.SECURITY_ENABLED ? "Security" : "Distribution";
  2363.  
  2364. if ((groupTypeFlags & GroupTypeFlags.UNIVERSAL_GROUP) == GroupTypeFlags.UNIVERSAL_GROUP)
  2365. {
  2366. GroupScope = "Universal";
  2367. }
  2368. else if ((groupTypeFlags & GroupTypeFlags.GLOBAL_GROUP) == GroupTypeFlags.GLOBAL_GROUP)
  2369. {
  2370. GroupScope = "Global";
  2371. }
  2372. else if ((groupTypeFlags & GroupTypeFlags.DOMAIN_LOCAL_GROUP) == GroupTypeFlags.DOMAIN_LOCAL_GROUP)
  2373. {
  2374. GroupScope = "DomainLocal";
  2375. }
  2376. }
  2377. if (AdGroup.Properties["sidhistory"].Count >= 1)
  2378. {
  2379. string sids = "";
  2380. for (int i = 0; i < AdGroup.Properties["sidhistory"].Count; i++)
  2381. {
  2382. var history = AdGroup.Properties["sidhistory"][i];
  2383. sids = sids + "," + Convert.ToString(new SecurityIdentifier((byte[])history, 0));
  2384. }
  2385. SIDHistory = sids.TrimStart(',');
  2386. }
  2387.  
  2388. PSObject GroupObj = new PSObject();
  2389. GroupObj.Members.Add(new PSNoteProperty("Name", AdGroup.Properties["samaccountname"][0]));
  2390. GroupObj.Members.Add(new PSNoteProperty("AdminCount", (AdGroup.Properties["admincount"].Count != 0 ? AdGroup.Properties["admincount"][0] : "")));
  2391. GroupObj.Members.Add(new PSNoteProperty("GroupCategory", GroupCategory));
  2392. GroupObj.Members.Add(new PSNoteProperty("GroupScope", GroupScope));
  2393. GroupObj.Members.Add(new PSNoteProperty("ManagedBy", ManagedBy));
  2394. GroupObj.Members.Add(new PSNoteProperty("SID", Convert.ToString(new SecurityIdentifier((byte[])AdGroup.Properties["objectSID"][0], 0))));
  2395. GroupObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  2396. GroupObj.Members.Add(new PSNoteProperty("Description", (AdGroup.Properties["Description"].Count != 0 ? CleanString(AdGroup.Properties["Description"][0]) : "")));
  2397. GroupObj.Members.Add(new PSNoteProperty("whenCreated", AdGroup.Properties["whencreated"][0]));
  2398. GroupObj.Members.Add(new PSNoteProperty("whenChanged", AdGroup.Properties["whenchanged"][0]));
  2399. GroupObj.Members.Add(new PSNoteProperty("DistinguishedName", CleanString(AdGroup.Properties["distinguishedname"][0])));
  2400. GroupObj.Members.Add(new PSNoteProperty("CanonicalName", AdGroup.Properties["canonicalname"][0]));
  2401. return new PSObject[] { GroupObj };
  2402. }
  2403. catch (Exception e)
  2404. {
  2405. Console.WriteLine("{0} Exception caught.", e);
  2406. return new PSObject[] { };
  2407. }
  2408. }
  2409. }
  2410.  
  2411. class GroupRecordDictionaryProcessor : IRecordProcessor
  2412. {
  2413. public PSObject[] processRecord(Object record)
  2414. {
  2415. try
  2416. {
  2417. SearchResult AdGroup = (SearchResult) record;
  2418. LDAPClass.AdGroupDictionary.Add((Convert.ToString(new SecurityIdentifier((byte[])AdGroup.Properties["objectSID"][0], 0))),(Convert.ToString(AdGroup.Properties["samaccountname"][0])));
  2419. return new PSObject[] { };
  2420. }
  2421. catch (Exception e)
  2422. {
  2423. Console.WriteLine("{0} Exception caught.", e);
  2424. return new PSObject[] { };
  2425. }
  2426. }
  2427. }
  2428.  
  2429. class GroupMemberRecordProcessor : IRecordProcessor
  2430. {
  2431. public PSObject[] processRecord(Object record)
  2432. {
  2433. try
  2434. {
  2435. // https://github.com/BloodHoundAD/BloodHound/blob/master/PowerShell/BloodHound.ps1
  2436. SearchResult AdGroup = (SearchResult) record;
  2437. List<PSObject> GroupsList = new List<PSObject>();
  2438. string SamAccountType = AdGroup.Properties["samaccounttype"].Count != 0 ? Convert.ToString(AdGroup.Properties["samaccounttype"][0]) : "";
  2439. string AccountType = "";
  2440. string GroupName = "";
  2441. string MemberUserName = "-";
  2442. string MemberName = "";
  2443.  
  2444. if (Groups.Contains(SamAccountType))
  2445. {
  2446. AccountType = "group";
  2447. MemberName = ((Convert.ToString(AdGroup.Properties["DistinguishedName"][0])).Split(',')[0]).Split('=')[1];
  2448. foreach (String GroupMember in AdGroup.Properties["memberof"])
  2449. {
  2450. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  2451. PSObject GroupMemberObj = new PSObject();
  2452. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  2453. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  2454. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  2455. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  2456. GroupsList.Add( GroupMemberObj );
  2457. }
  2458. }
  2459. if (Users.Contains(SamAccountType))
  2460. {
  2461. AccountType = "user";
  2462. MemberName = ((Convert.ToString(AdGroup.Properties["DistinguishedName"][0])).Split(',')[0]).Split('=')[1];
  2463. MemberUserName = Convert.ToString(AdGroup.Properties["sAMAccountName"][0]);
  2464. String PrimaryGroupID = Convert.ToString(AdGroup.Properties["primaryGroupID"][0]);
  2465. try
  2466. {
  2467. GroupName = LDAPClass.AdGroupDictionary[LDAPClass.DomainSID + "-" + PrimaryGroupID];
  2468. }
  2469. catch //(Exception e)
  2470. {
  2471. //Console.WriteLine("{0} Exception caught.", e);
  2472. GroupName = PrimaryGroupID;
  2473. }
  2474.  
  2475. {
  2476. PSObject GroupMemberObj = new PSObject();
  2477. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  2478. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  2479. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  2480. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  2481. GroupsList.Add( GroupMemberObj );
  2482. }
  2483.  
  2484. foreach (String GroupMember in AdGroup.Properties["memberof"])
  2485. {
  2486. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  2487. PSObject GroupMemberObj = new PSObject();
  2488. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  2489. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  2490. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  2491. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  2492. GroupsList.Add( GroupMemberObj );
  2493. }
  2494. }
  2495. if (Computers.Contains(SamAccountType))
  2496. {
  2497. AccountType = "computer";
  2498. MemberName = ((Convert.ToString(AdGroup.Properties["DistinguishedName"][0])).Split(',')[0]).Split('=')[1];
  2499. MemberUserName = Convert.ToString(AdGroup.Properties["sAMAccountName"][0]);
  2500. String PrimaryGroupID = Convert.ToString(AdGroup.Properties["primaryGroupID"][0]);
  2501. try
  2502. {
  2503. GroupName = LDAPClass.AdGroupDictionary[LDAPClass.DomainSID + "-" + PrimaryGroupID];
  2504. }
  2505. catch //(Exception e)
  2506. {
  2507. //Console.WriteLine("{0} Exception caught.", e);
  2508. GroupName = PrimaryGroupID;
  2509. }
  2510.  
  2511. {
  2512. PSObject GroupMemberObj = new PSObject();
  2513. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  2514. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  2515. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  2516. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  2517. GroupsList.Add( GroupMemberObj );
  2518. }
  2519.  
  2520. foreach (String GroupMember in AdGroup.Properties["memberof"])
  2521. {
  2522. GroupName = ((Convert.ToString(GroupMember)).Split(',')[0]).Split('=')[1];
  2523. PSObject GroupMemberObj = new PSObject();
  2524. GroupMemberObj.Members.Add(new PSNoteProperty("Group Name", GroupName));
  2525. GroupMemberObj.Members.Add(new PSNoteProperty("Member UserName", MemberUserName));
  2526. GroupMemberObj.Members.Add(new PSNoteProperty("Member Name", MemberName));
  2527. GroupMemberObj.Members.Add(new PSNoteProperty("AccountType", AccountType));
  2528. GroupsList.Add( GroupMemberObj );
  2529. }
  2530. }
  2531. if (TrustAccounts.Contains(SamAccountType))
  2532. {
  2533. // TO DO
  2534. }
  2535. return GroupsList.ToArray();
  2536. }
  2537. catch (Exception e)
  2538. {
  2539. Console.WriteLine("{0} Exception caught.", e);
  2540. return new PSObject[] { };
  2541. }
  2542. }
  2543. }
  2544.  
  2545. class OURecordProcessor : IRecordProcessor
  2546. {
  2547. public PSObject[] processRecord(Object record)
  2548. {
  2549. try
  2550. {
  2551. SearchResult AdOU = (SearchResult) record;
  2552.  
  2553. PSObject OUObj = new PSObject();
  2554. OUObj.Members.Add(new PSNoteProperty("Name", AdOU.Properties["name"][0]));
  2555. OUObj.Members.Add(new PSNoteProperty("Depth", ((Convert.ToString(AdOU.Properties["distinguishedname"][0]).Split(new string[] { "OU=" }, StringSplitOptions.None)).Length -1)));
  2556. OUObj.Members.Add(new PSNoteProperty("Description", (AdOU.Properties["description"].Count != 0 ? AdOU.Properties["description"][0] : "")));
  2557. OUObj.Members.Add(new PSNoteProperty("whenCreated", AdOU.Properties["whencreated"][0]));
  2558. OUObj.Members.Add(new PSNoteProperty("whenChanged", AdOU.Properties["whenchanged"][0]));
  2559. OUObj.Members.Add(new PSNoteProperty("DistinguishedName", AdOU.Properties["distinguishedname"][0]));
  2560. return new PSObject[] { OUObj };
  2561. }
  2562. catch (Exception e)
  2563. {
  2564. Console.WriteLine("{0} Exception caught.", e);
  2565. return new PSObject[] { };
  2566. }
  2567. }
  2568. }
  2569.  
  2570. class GPORecordProcessor : IRecordProcessor
  2571. {
  2572. public PSObject[] processRecord(Object record)
  2573. {
  2574. try
  2575. {
  2576. SearchResult AdGPO = (SearchResult) record;
  2577.  
  2578. PSObject GPOObj = new PSObject();
  2579. GPOObj.Members.Add(new PSNoteProperty("DisplayName", CleanString(AdGPO.Properties["displayname"][0])));
  2580. GPOObj.Members.Add(new PSNoteProperty("GUID", CleanString(AdGPO.Properties["name"][0])));
  2581. GPOObj.Members.Add(new PSNoteProperty("whenCreated", AdGPO.Properties["whenCreated"][0]));
  2582. GPOObj.Members.Add(new PSNoteProperty("whenChanged", AdGPO.Properties["whenChanged"][0]));
  2583. GPOObj.Members.Add(new PSNoteProperty("DistinguishedName", CleanString(AdGPO.Properties["distinguishedname"][0])));
  2584. GPOObj.Members.Add(new PSNoteProperty("FilePath", AdGPO.Properties["gpcfilesyspath"][0]));
  2585. return new PSObject[] { GPOObj };
  2586. }
  2587. catch (Exception e)
  2588. {
  2589. Console.WriteLine("{0} Exception caught.", e);
  2590. return new PSObject[] { };
  2591. }
  2592. }
  2593. }
  2594.  
  2595. class GPORecordDictionaryProcessor : IRecordProcessor
  2596. {
  2597. public PSObject[] processRecord(Object record)
  2598. {
  2599. try
  2600. {
  2601. SearchResult AdGPO = (SearchResult) record;
  2602. LDAPClass.AdGPODictionary.Add((Convert.ToString(AdGPO.Properties["distinguishedname"][0]).ToUpper()), (Convert.ToString(AdGPO.Properties["displayname"][0])));
  2603. return new PSObject[] { };
  2604. }
  2605. catch (Exception e)
  2606. {
  2607. Console.WriteLine("{0} Exception caught.", e);
  2608. return new PSObject[] { };
  2609. }
  2610. }
  2611. }
  2612.  
  2613. class SOMRecordProcessor : IRecordProcessor
  2614. {
  2615. public PSObject[] processRecord(Object record)
  2616. {
  2617. try
  2618. {
  2619. SearchResult AdSOM = (SearchResult) record;
  2620.  
  2621. List<PSObject> SOMsList = new List<PSObject>();
  2622. int Depth = 0;
  2623. bool BlockInheritance = false;
  2624. bool? LinkEnabled = null;
  2625. bool? Enforced = null;
  2626. String gPLink = (AdSOM.Properties["gPLink"].Count != 0 ? Convert.ToString(AdSOM.Properties["gPLink"][0]) : "");
  2627. String GPOName = null;
  2628.  
  2629. Depth = ((Convert.ToString(AdSOM.Properties["distinguishedname"][0]).Split(new string[] { "OU=" }, StringSplitOptions.None)).Length -1);
  2630. if (AdSOM.Properties["gPOptions"].Count != 0)
  2631. {
  2632. if ((int) AdSOM.Properties["gPOptions"][0] == 1)
  2633. {
  2634. BlockInheritance = true;
  2635. }
  2636. }
  2637. var GPLinks = gPLink.Split(']', '[').Where(x => x.StartsWith("LDAP"));
  2638. int Order = (GPLinks.ToArray()).Length;
  2639. if (Order == 0)
  2640. {
  2641. PSObject SOMObj = new PSObject();
  2642. SOMObj.Members.Add(new PSNoteProperty("Name", AdSOM.Properties["name"][0]));
  2643. SOMObj.Members.Add(new PSNoteProperty("Depth", Depth));
  2644. SOMObj.Members.Add(new PSNoteProperty("DistinguishedName", AdSOM.Properties["distinguishedname"][0]));
  2645. SOMObj.Members.Add(new PSNoteProperty("Link Order", null));
  2646. SOMObj.Members.Add(new PSNoteProperty("GPO", GPOName));
  2647. SOMObj.Members.Add(new PSNoteProperty("Enforced", Enforced));
  2648. SOMObj.Members.Add(new PSNoteProperty("Link Enabled", LinkEnabled));
  2649. SOMObj.Members.Add(new PSNoteProperty("BlockInheritance", BlockInheritance));
  2650. SOMObj.Members.Add(new PSNoteProperty("gPLink", gPLink));
  2651. SOMObj.Members.Add(new PSNoteProperty("gPOptions", (AdSOM.Properties["gpoptions"].Count != 0 ? AdSOM.Properties["gpoptions"][0] : "")));
  2652. SOMsList.Add( SOMObj );
  2653. }
  2654. foreach (String link in GPLinks)
  2655. {
  2656. String[] linksplit = link.Split('/', ';');
  2657. if (!Convert.ToBoolean((Convert.ToInt32(linksplit[3]) & 1)))
  2658. {
  2659. LinkEnabled = true;
  2660. }
  2661. else
  2662. {
  2663. LinkEnabled = false;
  2664. }
  2665. if (Convert.ToBoolean((Convert.ToInt32(linksplit[3]) & 2)))
  2666. {
  2667. Enforced = true;
  2668. }
  2669. else
  2670. {
  2671. Enforced = false;
  2672. }
  2673. GPOName = LDAPClass.AdGPODictionary.ContainsKey(linksplit[2].ToUpper()) ? LDAPClass.AdGPODictionary[linksplit[2].ToUpper()] : linksplit[2].Split('=',',')[1];
  2674. PSObject SOMObj = new PSObject();
  2675. SOMObj.Members.Add(new PSNoteProperty("Name", AdSOM.Properties["name"][0]));
  2676. SOMObj.Members.Add(new PSNoteProperty("Depth", Depth));
  2677. SOMObj.Members.Add(new PSNoteProperty("DistinguishedName", AdSOM.Properties["distinguishedname"][0]));
  2678. SOMObj.Members.Add(new PSNoteProperty("Link Order", Order));
  2679. SOMObj.Members.Add(new PSNoteProperty("GPO", GPOName));
  2680. SOMObj.Members.Add(new PSNoteProperty("Enforced", Enforced));
  2681. SOMObj.Members.Add(new PSNoteProperty("Link Enabled", LinkEnabled));
  2682. SOMObj.Members.Add(new PSNoteProperty("BlockInheritance", BlockInheritance));
  2683. SOMObj.Members.Add(new PSNoteProperty("gPLink", gPLink));
  2684. SOMObj.Members.Add(new PSNoteProperty("gPOptions", (AdSOM.Properties["gpoptions"].Count != 0 ? AdSOM.Properties["gpoptions"][0] : "")));
  2685. SOMsList.Add( SOMObj );
  2686. Order--;
  2687. }
  2688. return SOMsList.ToArray();
  2689. }
  2690. catch (Exception e)
  2691. {
  2692. Console.WriteLine("{0} Exception caught.", e);
  2693. return new PSObject[] { };
  2694. }
  2695. }
  2696. }
  2697.  
  2698. class PrinterRecordProcessor : IRecordProcessor
  2699. {
  2700. public PSObject[] processRecord(Object record)
  2701. {
  2702. try
  2703. {
  2704. SearchResult AdPrinter = (SearchResult) record;
  2705.  
  2706. PSObject PrinterObj = new PSObject();
  2707. PrinterObj.Members.Add(new PSNoteProperty("Name", AdPrinter.Properties["Name"][0]));
  2708. PrinterObj.Members.Add(new PSNoteProperty("ServerName", AdPrinter.Properties["serverName"][0]));
  2709. PrinterObj.Members.Add(new PSNoteProperty("ShareName", AdPrinter.Properties["printShareName"][0]));
  2710. PrinterObj.Members.Add(new PSNoteProperty("DriverName", AdPrinter.Properties["driverName"][0]));
  2711. PrinterObj.Members.Add(new PSNoteProperty("DriverVersion", AdPrinter.Properties["driverVersion"][0]));
  2712. PrinterObj.Members.Add(new PSNoteProperty("PortName", AdPrinter.Properties["portName"][0]));
  2713. PrinterObj.Members.Add(new PSNoteProperty("URL", AdPrinter.Properties["url"][0]));
  2714. PrinterObj.Members.Add(new PSNoteProperty("whenCreated", AdPrinter.Properties["whenCreated"][0]));
  2715. PrinterObj.Members.Add(new PSNoteProperty("whenChanged", AdPrinter.Properties["whenChanged"][0]));
  2716. return new PSObject[] { PrinterObj };
  2717. }
  2718. catch (Exception e)
  2719. {
  2720. Console.WriteLine("{0} Exception caught.", e);
  2721. return new PSObject[] { };
  2722. }
  2723. }
  2724. }
  2725.  
  2726. class ComputerRecordProcessor : IRecordProcessor
  2727. {
  2728. public PSObject[] processRecord(Object record)
  2729. {
  2730. try
  2731. {
  2732. SearchResult AdComputer = (SearchResult) record;
  2733. bool Dormant = false;
  2734. bool? Enabled = null;
  2735. bool PasswordNotChangedafterMaxAge = false;
  2736. bool? TrustedforDelegation = null;
  2737. bool? TrustedtoAuthforDelegation = null;
  2738. String DelegationType = null;
  2739. String DelegationProtocol = null;
  2740. String DelegationServices = null;
  2741. String StrIPAddress = null;
  2742. int? DaysSinceLastLogon = null;
  2743. int? DaysSinceLastPasswordChange = null;
  2744. DateTime? LastLogonDate = null;
  2745. DateTime? PasswordLastSet = null;
  2746.  
  2747. if (AdComputer.Properties["dnshostname"].Count != 0)
  2748. {
  2749. try
  2750. {
  2751. StrIPAddress = Convert.ToString(Dns.GetHostEntry(Convert.ToString(AdComputer.Properties["dnshostname"][0])).AddressList[0]);
  2752. }
  2753. catch
  2754. {
  2755. StrIPAddress = null;
  2756. }
  2757. }
  2758. // When the user is not allowed to query the UserAccountControl attribute.
  2759. if (AdComputer.Properties["useraccountcontrol"].Count != 0)
  2760. {
  2761. var userFlags = (UACFlags) AdComputer.Properties["useraccountcontrol"][0];
  2762. Enabled = !((userFlags & UACFlags.ACCOUNTDISABLE) == UACFlags.ACCOUNTDISABLE);
  2763. TrustedforDelegation = (userFlags & UACFlags.TRUSTED_FOR_DELEGATION) == UACFlags.TRUSTED_FOR_DELEGATION;
  2764. TrustedtoAuthforDelegation = (userFlags & UACFlags.TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) == UACFlags.TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION;
  2765. }
  2766. if (AdComputer.Properties["lastlogontimestamp"].Count != 0)
  2767. {
  2768. LastLogonDate = DateTime.FromFileTime((long)(AdComputer.Properties["lastlogontimestamp"][0]));
  2769. DaysSinceLastLogon = Math.Abs((Date1 - (DateTime)LastLogonDate).Days);
  2770. if (DaysSinceLastLogon > DormantTimeSpan)
  2771. {
  2772. Dormant = true;
  2773. }
  2774. }
  2775. if (AdComputer.Properties["pwdlastset"].Count != 0)
  2776. {
  2777. PasswordLastSet = DateTime.FromFileTime((long)(AdComputer.Properties["pwdlastset"][0]));
  2778. DaysSinceLastPasswordChange = Math.Abs((Date1 - (DateTime)PasswordLastSet).Days);
  2779. if (DaysSinceLastPasswordChange > PassMaxAge)
  2780. {
  2781. PasswordNotChangedafterMaxAge = true;
  2782. }
  2783. }
  2784. if ( ((bool) TrustedforDelegation) && ((int) AdComputer.Properties["primarygroupid"][0] == 515) )
  2785. {
  2786. DelegationType = "Unconstrained";
  2787. DelegationServices = "Any";
  2788. }
  2789. if (AdComputer.Properties["msDS-AllowedToDelegateTo"].Count >= 1)
  2790. {
  2791. DelegationType = "Constrained";
  2792. for (int i = 0; i < AdComputer.Properties["msDS-AllowedToDelegateTo"].Count; i++)
  2793. {
  2794. var delegateto = AdComputer.Properties["msDS-AllowedToDelegateTo"][i];
  2795. DelegationServices = DelegationServices + "," + Convert.ToString(delegateto);
  2796. }
  2797. DelegationServices = DelegationServices.TrimStart(',');
  2798. }
  2799. if ((bool) TrustedtoAuthforDelegation)
  2800. {
  2801. DelegationProtocol = "Any";
  2802. }
  2803. else if (DelegationType != null)
  2804. {
  2805. DelegationProtocol = "Kerberos";
  2806. }
  2807. string SIDHistory = "";
  2808. if (AdComputer.Properties["sidhistory"].Count >= 1)
  2809. {
  2810. string sids = "";
  2811. for (int i = 0; i < AdComputer.Properties["sidhistory"].Count; i++)
  2812. {
  2813. var history = AdComputer.Properties["sidhistory"][i];
  2814. sids = sids + "," + Convert.ToString(new SecurityIdentifier((byte[])history, 0));
  2815. }
  2816. SIDHistory = sids.TrimStart(',');
  2817. }
  2818. String OperatingSystem = CleanString((AdComputer.Properties["operatingsystem"].Count != 0 ? AdComputer.Properties["operatingsystem"][0] : "-") + " " + (AdComputer.Properties["operatingsystemhotfix"].Count != 0 ? AdComputer.Properties["operatingsystemhotfix"][0] : " ") + " " + (AdComputer.Properties["operatingsystemservicepack"].Count != 0 ? AdComputer.Properties["operatingsystemservicepack"][0] : " ") + " " + (AdComputer.Properties["operatingsystemversion"].Count != 0 ? AdComputer.Properties["operatingsystemversion"][0] : " "));
  2819.  
  2820. PSObject ComputerObj = new PSObject();
  2821. ComputerObj.Members.Add(new PSNoteProperty("Name", (AdComputer.Properties["name"].Count != 0 ? AdComputer.Properties["name"][0] : "")));
  2822. ComputerObj.Members.Add(new PSNoteProperty("DNSHostName", (AdComputer.Properties["dnshostname"].Count != 0 ? AdComputer.Properties["dnshostname"][0] : "")));
  2823. ComputerObj.Members.Add(new PSNoteProperty("Enabled", Enabled));
  2824. ComputerObj.Members.Add(new PSNoteProperty("IPv4Address", StrIPAddress));
  2825. ComputerObj.Members.Add(new PSNoteProperty("Operating System", OperatingSystem));
  2826. ComputerObj.Members.Add(new PSNoteProperty("Logon Age (days)", DaysSinceLastLogon));
  2827. ComputerObj.Members.Add(new PSNoteProperty("Password Age (days)", DaysSinceLastPasswordChange));
  2828. ComputerObj.Members.Add(new PSNoteProperty("Dormant (> " + DormantTimeSpan + " days)", Dormant));
  2829. ComputerObj.Members.Add(new PSNoteProperty("Password Age (> " + PassMaxAge + " days)", PasswordNotChangedafterMaxAge));
  2830. ComputerObj.Members.Add(new PSNoteProperty("Delegation Type", DelegationType));
  2831. ComputerObj.Members.Add(new PSNoteProperty("Delegation Protocol", DelegationProtocol));
  2832. ComputerObj.Members.Add(new PSNoteProperty("Delegation Services", DelegationServices));
  2833. ComputerObj.Members.Add(new PSNoteProperty("UserName", (AdComputer.Properties["samaccountname"].Count != 0 ? AdComputer.Properties["samaccountname"][0] : "")));
  2834. ComputerObj.Members.Add(new PSNoteProperty("Primary Group ID", (AdComputer.Properties["primarygroupid"].Count != 0 ? AdComputer.Properties["primarygroupid"][0] : "")));
  2835. ComputerObj.Members.Add(new PSNoteProperty("SID", Convert.ToString(new SecurityIdentifier((byte[])AdComputer.Properties["objectSID"][0], 0))));
  2836. ComputerObj.Members.Add(new PSNoteProperty("SIDHistory", SIDHistory));
  2837. ComputerObj.Members.Add(new PSNoteProperty("Description", (AdComputer.Properties["Description"].Count != 0 ? AdComputer.Properties["Description"][0] : "")));
  2838. ComputerObj.Members.Add(new PSNoteProperty("ms-ds-CreatorSid", (AdComputer.Properties["ms-ds-CreatorSid"].Count != 0 ? Convert.ToString(new SecurityIdentifier((byte[])AdComputer.Properties["ms-ds-CreatorSid"][0], 0)) : "")));
  2839. ComputerObj.Members.Add(new PSNoteProperty("Last Logon Date", LastLogonDate));
  2840. ComputerObj.Members.Add(new PSNoteProperty("Password LastSet", PasswordLastSet));
  2841. ComputerObj.Members.Add(new PSNoteProperty("UserAccountControl", (AdComputer.Properties["useraccountcontrol"].Count != 0 ? AdComputer.Properties["useraccountcontrol"][0] : "")));
  2842. ComputerObj.Members.Add(new PSNoteProperty("whenCreated", AdComputer.Properties["whencreated"][0]));
  2843. ComputerObj.Members.Add(new PSNoteProperty("whenChanged", AdComputer.Properties["whenchanged"][0]));
  2844. ComputerObj.Members.Add(new PSNoteProperty("Distinguished Name", AdComputer.Properties["distinguishedname"][0]));
  2845. return new PSObject[] { ComputerObj };
  2846. }
  2847. catch (Exception e)
  2848. {
  2849. Console.WriteLine("{0} Exception caught.", e);
  2850. return new PSObject[] { };
  2851. }
  2852. }
  2853. }
  2854.  
  2855. class ComputerSPNRecordProcessor : IRecordProcessor
  2856. {
  2857. public PSObject[] processRecord(Object record)
  2858. {
  2859. try
  2860. {
  2861. SearchResult AdComputer = (SearchResult) record;
  2862. List<PSObject> SPNList = new List<PSObject>();
  2863.  
  2864. foreach (String SPN in AdComputer.Properties["serviceprincipalname"])
  2865. {
  2866. String[] SPNArray = SPN.Split('/');
  2867. bool flag = true;
  2868. foreach (PSObject Obj in SPNList)
  2869. {
  2870. if ( (String) Obj.Members["Service"].Value == SPNArray[0] )
  2871. {
  2872. Obj.Members["Host"].Value = String.Join(",", (Obj.Members["Host"].Value + "," + SPNArray[1]).Split(',').Distinct().ToArray());
  2873. flag = false;
  2874. }
  2875. }
  2876. if (flag)
  2877. {
  2878. PSObject ComputerSPNObj = new PSObject();
  2879. ComputerSPNObj.Members.Add(new PSNoteProperty("Name", AdComputer.Properties["name"][0]));
  2880. ComputerSPNObj.Members.Add(new PSNoteProperty("Service", SPNArray[0]));
  2881. ComputerSPNObj.Members.Add(new PSNoteProperty("Host", SPNArray[1]));
  2882. SPNList.Add( ComputerSPNObj );
  2883. }
  2884. }
  2885. return SPNList.ToArray();
  2886. }
  2887. catch (Exception e)
  2888. {
  2889. Console.WriteLine("{0} Exception caught.", e);
  2890. return new PSObject[] { };
  2891. }
  2892. }
  2893. }
  2894.  
  2895. class LAPSRecordProcessor : IRecordProcessor
  2896. {
  2897. public PSObject[] processRecord(Object record)
  2898. {
  2899. try
  2900. {
  2901. SearchResult AdComputer = (SearchResult) record;
  2902. bool PasswordStored = false;
  2903. DateTime? CurrentExpiration = null;
  2904. if (AdComputer.Properties["ms-mcs-admpwdexpirationtime"].Count != 0)
  2905. {
  2906. CurrentExpiration = DateTime.FromFileTime((long)(AdComputer.Properties["ms-mcs-admpwdexpirationtime"][0]));
  2907. PasswordStored = true;
  2908. }
  2909. PSObject LAPSObj = new PSObject();
  2910. LAPSObj.Members.Add(new PSNoteProperty("Hostname", (AdComputer.Properties["dnshostname"].Count != 0 ? AdComputer.Properties["dnshostname"][0] : AdComputer.Properties["cn"][0] )));
  2911. LAPSObj.Members.Add(new PSNoteProperty("Stored", PasswordStored));
  2912. LAPSObj.Members.Add(new PSNoteProperty("Readable", (AdComputer.Properties["ms-mcs-admpwd"].Count != 0 ? true : false)));
  2913. LAPSObj.Members.Add(new PSNoteProperty("Password", (AdComputer.Properties["ms-mcs-admpwd"].Count != 0 ? AdComputer.Properties["ms-mcs-admpwd"][0] : null)));
  2914. LAPSObj.Members.Add(new PSNoteProperty("Expiration", CurrentExpiration));
  2915. return new PSObject[] { LAPSObj };
  2916. }
  2917. catch (Exception e)
  2918. {
  2919. Console.WriteLine("{0} Exception caught.", e);
  2920. return new PSObject[] { };
  2921. }
  2922. }
  2923. }
  2924.  
  2925. class SIDRecordDictionaryProcessor : IRecordProcessor
  2926. {
  2927. public PSObject[] processRecord(Object record)
  2928. {
  2929. try
  2930. {
  2931. SearchResult AdObject = (SearchResult) record;
  2932. switch (Convert.ToString(AdObject.Properties["objectclass"][AdObject.Properties["objectclass"].Count-1]))
  2933. {
  2934. case "user":
  2935. case "computer":
  2936. case "group":
  2937. LDAPClass.AdSIDDictionary.Add(Convert.ToString(new SecurityIdentifier((byte[])AdObject.Properties["objectSID"][0], 0)), (Convert.ToString(AdObject.Properties["name"][0])));
  2938. break;
  2939. }
  2940. return new PSObject[] { };
  2941. }
  2942. catch (Exception e)
  2943. {
  2944. Console.WriteLine("{0} Exception caught.", e);
  2945. return new PSObject[] { };
  2946. }
  2947. }
  2948. }
  2949.  
  2950. class DACLRecordProcessor : IRecordProcessor
  2951. {
  2952. public PSObject[] processRecord(Object record)
  2953. {
  2954. try
  2955. {
  2956. SearchResult AdObject = (SearchResult) record;
  2957. byte[] ntSecurityDescriptor = null;
  2958. String Name = null;
  2959. String Type = null;
  2960. List<PSObject> DACLList = new List<PSObject>();
  2961.  
  2962. Name = Convert.ToString(AdObject.Properties["name"][0]);
  2963.  
  2964. switch (Convert.ToString(AdObject.Properties["objectclass"][AdObject.Properties["objectclass"].Count-1]))
  2965. {
  2966. case "user":
  2967. Type = "User";
  2968. break;
  2969. case "computer":
  2970. Type = "Computer";
  2971. break;
  2972. case "group":
  2973. Type = "Group";
  2974. break;
  2975. case "container":
  2976. Type = "Container";
  2977. break;
  2978. case "groupPolicyContainer":
  2979. Type = "GPO";
  2980. Name = Convert.ToString(AdObject.Properties["displayname"][0]);
  2981. break;
  2982. case "organizationalUnit":
  2983. Type = "OU";
  2984. break;
  2985. case "domainDNS":
  2986. Type = "Domain";
  2987. break;
  2988. default:
  2989. Type = Convert.ToString(AdObject.Properties["objectclass"][AdObject.Properties["objectclass"].Count-1]);
  2990. break;
  2991. }
  2992.  
  2993. // When the user is not allowed to query the ntsecuritydescriptor attribute.
  2994. if (AdObject.Properties["ntsecuritydescriptor"].Count != 0)
  2995. {
  2996. ntSecurityDescriptor = (byte[]) AdObject.Properties["ntsecuritydescriptor"][0];
  2997. }
  2998. else
  2999. {
  3000. DirectoryEntry AdObjectEntry = ((SearchResult)record).GetDirectoryEntry();
  3001. ntSecurityDescriptor = (byte[]) AdObjectEntry.ObjectSecurity.GetSecurityDescriptorBinaryForm();
  3002. }
  3003. if (ntSecurityDescriptor != null)
  3004. {
  3005. DirectoryObjectSecurity DirObjSec = new ActiveDirectorySecurity();
  3006. DirObjSec.SetSecurityDescriptorBinaryForm(ntSecurityDescriptor);
  3007. AuthorizationRuleCollection AccessRules = (AuthorizationRuleCollection) DirObjSec.GetAccessRules(true,true,typeof(System.Security.Principal.NTAccount));
  3008. foreach (ActiveDirectoryAccessRule Rule in AccessRules)
  3009. {
  3010. String IdentityReference = Convert.ToString(Rule.IdentityReference);
  3011. String Owner = Convert.ToString(DirObjSec.GetOwner(typeof(System.Security.Principal.SecurityIdentifier)));
  3012. PSObject ObjectObj = new PSObject();
  3013. ObjectObj.Members.Add(new PSNoteProperty("Name", CleanString(Name)));
  3014. ObjectObj.Members.Add(new PSNoteProperty("Type", Type));
  3015. ObjectObj.Members.Add(new PSNoteProperty("ObjectTypeName", LDAPClass.GUIDs[Convert.ToString(Rule.ObjectType)]));
  3016. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectTypeName", LDAPClass.GUIDs[Convert.ToString(Rule.InheritedObjectType)]));
  3017. ObjectObj.Members.Add(new PSNoteProperty("ActiveDirectoryRights", Rule.ActiveDirectoryRights));
  3018. ObjectObj.Members.Add(new PSNoteProperty("AccessControlType", Rule.AccessControlType));
  3019. ObjectObj.Members.Add(new PSNoteProperty("IdentityReferenceName", LDAPClass.AdSIDDictionary.ContainsKey(IdentityReference) ? LDAPClass.AdSIDDictionary[IdentityReference] : IdentityReference));
  3020. ObjectObj.Members.Add(new PSNoteProperty("OwnerName", LDAPClass.AdSIDDictionary.ContainsKey(Owner) ? LDAPClass.AdSIDDictionary[Owner] : Owner));
  3021. ObjectObj.Members.Add(new PSNoteProperty("Inherited", Rule.IsInherited));
  3022. ObjectObj.Members.Add(new PSNoteProperty("ObjectFlags", Rule.ObjectFlags));
  3023. ObjectObj.Members.Add(new PSNoteProperty("InheritanceFlags", Rule.InheritanceFlags));
  3024. ObjectObj.Members.Add(new PSNoteProperty("InheritanceType", Rule.InheritanceType));
  3025. ObjectObj.Members.Add(new PSNoteProperty("PropagationFlags", Rule.PropagationFlags));
  3026. ObjectObj.Members.Add(new PSNoteProperty("ObjectType", Rule.ObjectType));
  3027. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectType", Rule.InheritedObjectType));
  3028. ObjectObj.Members.Add(new PSNoteProperty("IdentityReference", Rule.IdentityReference));
  3029. ObjectObj.Members.Add(new PSNoteProperty("Owner", Owner));
  3030. ObjectObj.Members.Add(new PSNoteProperty("DistinguishedName", AdObject.Properties["distinguishedname"][0]));
  3031. DACLList.Add( ObjectObj );
  3032. }
  3033. }
  3034.  
  3035. return DACLList.ToArray();
  3036. }
  3037. catch (Exception e)
  3038. {
  3039. Console.WriteLine("{0} Exception caught.", e);
  3040. return new PSObject[] { };
  3041. }
  3042. }
  3043. }
  3044.  
  3045. class SACLRecordProcessor : IRecordProcessor
  3046. {
  3047. public PSObject[] processRecord(Object record)
  3048. {
  3049. try
  3050. {
  3051. SearchResult AdObject = (SearchResult) record;
  3052. byte[] ntSecurityDescriptor = null;
  3053. String Name = null;
  3054. String Type = null;
  3055. List<PSObject> SACLList = new List<PSObject>();
  3056.  
  3057. Name = Convert.ToString(AdObject.Properties["name"][0]);
  3058.  
  3059. switch (Convert.ToString(AdObject.Properties["objectclass"][AdObject.Properties["objectclass"].Count-1]))
  3060. {
  3061. case "user":
  3062. Type = "User";
  3063. break;
  3064. case "computer":
  3065. Type = "Computer";
  3066. break;
  3067. case "group":
  3068. Type = "Group";
  3069. break;
  3070. case "container":
  3071. Type = "Container";
  3072. break;
  3073. case "groupPolicyContainer":
  3074. Type = "GPO";
  3075. Name = Convert.ToString(AdObject.Properties["displayname"][0]);
  3076. break;
  3077. case "organizationalUnit":
  3078. Type = "OU";
  3079. break;
  3080. case "domainDNS":
  3081. Type = "Domain";
  3082. break;
  3083. default:
  3084. Type = Convert.ToString(AdObject.Properties["objectclass"][AdObject.Properties["objectclass"].Count-1]);
  3085. break;
  3086. }
  3087.  
  3088. // When the user is not allowed to query the ntsecuritydescriptor attribute.
  3089. if (AdObject.Properties["ntsecuritydescriptor"].Count != 0)
  3090. {
  3091. ntSecurityDescriptor = (byte[]) AdObject.Properties["ntsecuritydescriptor"][0];
  3092. }
  3093. else
  3094. {
  3095. DirectoryEntry AdObjectEntry = ((SearchResult)record).GetDirectoryEntry();
  3096. ntSecurityDescriptor = (byte[]) AdObjectEntry.ObjectSecurity.GetSecurityDescriptorBinaryForm();
  3097. }
  3098. if (ntSecurityDescriptor != null)
  3099. {
  3100. DirectoryObjectSecurity DirObjSec = new ActiveDirectorySecurity();
  3101. DirObjSec.SetSecurityDescriptorBinaryForm(ntSecurityDescriptor);
  3102. AuthorizationRuleCollection AuditRules = (AuthorizationRuleCollection) DirObjSec.GetAuditRules(true,true,typeof(System.Security.Principal.NTAccount));
  3103. foreach (ActiveDirectoryAuditRule Rule in AuditRules)
  3104. {
  3105. String IdentityReference = Convert.ToString(Rule.IdentityReference);
  3106. PSObject ObjectObj = new PSObject();
  3107. ObjectObj.Members.Add(new PSNoteProperty("Name", CleanString(Name)));
  3108. ObjectObj.Members.Add(new PSNoteProperty("Type", Type));
  3109. ObjectObj.Members.Add(new PSNoteProperty("ObjectTypeName", LDAPClass.GUIDs[Convert.ToString(Rule.ObjectType)]));
  3110. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectTypeName", LDAPClass.GUIDs[Convert.ToString(Rule.InheritedObjectType)]));
  3111. ObjectObj.Members.Add(new PSNoteProperty("ActiveDirectoryRights", Rule.ActiveDirectoryRights));
  3112. ObjectObj.Members.Add(new PSNoteProperty("IdentityReferenceName", LDAPClass.AdSIDDictionary.ContainsKey(IdentityReference) ? LDAPClass.AdSIDDictionary[IdentityReference] : IdentityReference));
  3113. ObjectObj.Members.Add(new PSNoteProperty("AuditFlags", Rule.AuditFlags));
  3114. ObjectObj.Members.Add(new PSNoteProperty("ObjectFlags", Rule.ObjectFlags));
  3115. ObjectObj.Members.Add(new PSNoteProperty("InheritanceFlags", Rule.InheritanceFlags));
  3116. ObjectObj.Members.Add(new PSNoteProperty("InheritanceType", Rule.InheritanceType));
  3117. ObjectObj.Members.Add(new PSNoteProperty("Inherited", Rule.IsInherited));
  3118. ObjectObj.Members.Add(new PSNoteProperty("PropagationFlags", Rule.PropagationFlags));
  3119. ObjectObj.Members.Add(new PSNoteProperty("ObjectType", Rule.ObjectType));
  3120. ObjectObj.Members.Add(new PSNoteProperty("InheritedObjectType", Rule.InheritedObjectType));
  3121. ObjectObj.Members.Add(new PSNoteProperty("IdentityReference", Rule.IdentityReference));
  3122. SACLList.Add( ObjectObj );
  3123. }
  3124. }
  3125.  
  3126. return SACLList.ToArray();
  3127. }
  3128. catch (Exception e)
  3129. {
  3130. Console.WriteLine("{0} Exception caught.", e);
  3131. return new PSObject[] { };
  3132. }
  3133. }
  3134. }
  3135.  
  3136. //The interface and implmentation class used to handle the results (this implementation just writes the strings to a file)
  3137.  
  3138. interface IResultsHandler
  3139. {
  3140. void processResults(Object[] t);
  3141.  
  3142. Object[] finalise();
  3143. }
  3144.  
  3145. class SimpleResultsHandler : IResultsHandler
  3146. {
  3147. private Object lockObj = new Object();
  3148. private List<Object> processed = new List<Object>();
  3149.  
  3150. public SimpleResultsHandler()
  3151. {
  3152. }
  3153.  
  3154. public void processResults(Object[] results)
  3155. {
  3156. lock (lockObj)
  3157. {
  3158. if (results.Length != 0)
  3159. {
  3160. for (var i = 0; i < results.Length; i++)
  3161. {
  3162. processed.Add((PSObject)results[i]);
  3163. }
  3164. }
  3165. }
  3166. }
  3167.  
  3168. public Object[] finalise()
  3169. {
  3170. return processed.ToArray();
  3171. }
  3172. }
  3173. }
  3174. }
  3175. "@
  3176.  
  3177. #Add-Type -TypeDefinition $Source -ReferencedAssemblies ([System.String[]]@(([system.reflection.assembly]::LoadWithPartialName("Microsoft.ActiveDirectory.Management")).Location,([system.reflection.assembly]::LoadWithPartialName("System.DirectoryServices")).Location))
  3178.  
  3179. # modified version from https://github.com/vletoux/SmbScanner/blob/master/smbscanner.ps1
  3180. $PingCastleSMBScannerSource = @"
  3181. using System;
  3182. using System.Collections.Generic;
  3183. using System.Diagnostics;
  3184. using System.IO;
  3185. using System.Net;
  3186. using System.Net.Sockets;
  3187. using System.Text;
  3188. using System.Runtime.InteropServices;
  3189. using System.Management.Automation;
  3190.  
  3191. namespace ADRecon
  3192. {
  3193. public class PingCastleScannersSMBScanner
  3194. {
  3195. [StructLayout(LayoutKind.Explicit)]
  3196. struct SMB_Header {
  3197. [FieldOffset(0)]
  3198. public UInt32 Protocol;
  3199. [FieldOffset(4)]
  3200. public byte Command;
  3201. [FieldOffset(5)]
  3202. public int Status;
  3203. [FieldOffset(9)]
  3204. public byte Flags;
  3205. [FieldOffset(10)]
  3206. public UInt16 Flags2;
  3207. [FieldOffset(12)]
  3208. public UInt16 PIDHigh;
  3209. [FieldOffset(14)]
  3210. public UInt64 SecurityFeatures;
  3211. [FieldOffset(22)]
  3212. public UInt16 Reserved;
  3213. [FieldOffset(24)]
  3214. public UInt16 TID;
  3215. [FieldOffset(26)]
  3216. public UInt16 PIDLow;
  3217. [FieldOffset(28)]
  3218. public UInt16 UID;
  3219. [FieldOffset(30)]
  3220. public UInt16 MID;
  3221. };
  3222. // https://msdn.microsoft.com/en-us/library/cc246529.aspx
  3223. [StructLayout(LayoutKind.Explicit)]
  3224. struct SMB2_Header {
  3225. [FieldOffset(0)]
  3226. public UInt32 ProtocolId;
  3227. [FieldOffset(4)]
  3228. public UInt16 StructureSize;
  3229. [FieldOffset(6)]
  3230. public UInt16 CreditCharge;
  3231. [FieldOffset(8)]
  3232. public UInt32 Status; // to do SMB3
  3233. [FieldOffset(12)]
  3234. public UInt16 Command;
  3235. [FieldOffset(14)]
  3236. public UInt16 CreditRequest_Response;
  3237. [FieldOffset(16)]
  3238. public UInt32 Flags;
  3239. [FieldOffset(20)]
  3240. public UInt32 NextCommand;
  3241. [FieldOffset(24)]
  3242. public UInt64 MessageId;
  3243. [FieldOffset(32)]
  3244. public UInt32 Reserved;
  3245. [FieldOffset(36)]
  3246. public UInt32 TreeId;
  3247. [FieldOffset(40)]
  3248. public UInt64 SessionId;
  3249. [FieldOffset(48)]
  3250. public UInt64 Signature1;
  3251. [FieldOffset(56)]
  3252. public UInt64 Signature2;
  3253. }
  3254. [StructLayout(LayoutKind.Explicit)]
  3255. struct SMB2_NegotiateRequest
  3256. {
  3257. [FieldOffset(0)]
  3258. public UInt16 StructureSize;
  3259. [FieldOffset(2)]
  3260. public UInt16 DialectCount;
  3261. [FieldOffset(4)]
  3262. public UInt16 SecurityMode;
  3263. [FieldOffset(6)]
  3264. public UInt16 Reserved;
  3265. [FieldOffset(8)]
  3266. public UInt32 Capabilities;
  3267. [FieldOffset(12)]
  3268. public Guid ClientGuid;
  3269. [FieldOffset(28)]
  3270. public UInt64 ClientStartTime;
  3271. [FieldOffset(36)]
  3272. public UInt16 DialectToTest;
  3273. }
  3274. const int SMB_COM_NEGOTIATE = 0x72;
  3275. const int SMB2_NEGOTIATE = 0;
  3276. const int SMB_FLAGS_CASE_INSENSITIVE = 0x08;
  3277. const int SMB_FLAGS_CANONICALIZED_PATHS = 0x10;
  3278. const int SMB_FLAGS2_LONG_NAMES = 0x0001;
  3279. const int SMB_FLAGS2_EAS = 0x0002;
  3280. const int SMB_FLAGS2_SECURITY_SIGNATURE_REQUIRED = 0x0010 ;
  3281. const int SMB_FLAGS2_IS_LONG_NAME = 0x0040;
  3282. const int SMB_FLAGS2_ESS = 0x0800;
  3283. const int SMB_FLAGS2_NT_STATUS = 0x4000;
  3284. const int SMB_FLAGS2_UNICODE = 0x8000;
  3285. const int SMB_DB_FORMAT_DIALECT = 0x02;
  3286. static byte[] GenerateSmbHeaderFromCommand(byte command)
  3287. {
  3288. SMB_Header header = new SMB_Header();
  3289. header.Protocol = 0x424D53FF;
  3290. header.Command = command;
  3291. header.Status = 0;
  3292. header.Flags = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS;
  3293. header.Flags2 = SMB_FLAGS2_LONG_NAMES | SMB_FLAGS2_EAS | SMB_FLAGS2_SECURITY_SIGNATURE_REQUIRED | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_ESS | SMB_FLAGS2_NT_STATUS | SMB_FLAGS2_UNICODE;
  3294. header.PIDHigh = 0;
  3295. header.SecurityFeatures = 0;
  3296. header.Reserved = 0;
  3297. header.TID = 0xffff;
  3298. header.PIDLow = 0xFEFF;
  3299. header.UID = 0;
  3300. header.MID = 0;
  3301. return getBytes(header);
  3302. }
  3303. static byte[] GenerateSmb2HeaderFromCommand(byte command)
  3304. {
  3305. SMB2_Header header = new SMB2_Header();
  3306. header.ProtocolId = 0x424D53FE;
  3307. header.Command = command;
  3308. header.StructureSize = 64;
  3309. header.Command = command;
  3310. header.MessageId = 0;
  3311. header.Reserved = 0xFEFF;
  3312. return getBytes(header);
  3313. }
  3314. static byte[] getBytes(object structure)
  3315. {
  3316. int size = Marshal.SizeOf(structure);
  3317. byte[] arr = new byte[size];
  3318. IntPtr ptr = Marshal.AllocHGlobal(size);
  3319. Marshal.StructureToPtr(structure, ptr, true);
  3320. Marshal.Copy(ptr, arr, 0, size);
  3321. Marshal.FreeHGlobal(ptr);
  3322. return arr;
  3323. }
  3324. static byte[] getDialect(string dialect)
  3325. {
  3326. byte[] dialectBytes = Encoding.ASCII.GetBytes(dialect);
  3327. byte[] output = new byte[dialectBytes.Length + 2];
  3328. output[0] = 2;
  3329. output[output.Length - 1] = 0;
  3330. Array.Copy(dialectBytes, 0, output, 1, dialectBytes.Length);
  3331. return output;
  3332. }
  3333. static byte[] GetNegotiateMessage(byte[] dialect)
  3334. {
  3335. byte[] output = new byte[dialect.Length + 3];
  3336. output[0] = 0;
  3337. output[1] = (byte) dialect.Length;
  3338. output[2] = 0;
  3339. Array.Copy(dialect, 0, output, 3, dialect.Length);
  3340. return output;
  3341. }
  3342. // MS-SMB2 2.2.3 SMB2 NEGOTIATE Request
  3343. static byte[] GetNegotiateMessageSmbv2(int DialectToTest)
  3344. {
  3345. SMB2_NegotiateRequest request = new SMB2_NegotiateRequest();
  3346. request.StructureSize = 36;
  3347. request.DialectCount = 1;
  3348. request.SecurityMode = 1; // signing enabled
  3349. request.ClientGuid = Guid.NewGuid();
  3350. request.DialectToTest = (UInt16) DialectToTest;
  3351. return getBytes(request);
  3352. }
  3353. static byte[] GetNegotiatePacket(byte[] header, byte[] smbPacket)
  3354. {
  3355. byte[] output = new byte[smbPacket.Length + header.Length + 4];
  3356. output[0] = 0;
  3357. output[1] = 0;
  3358. output[2] = 0;
  3359. output[3] = (byte)(smbPacket.Length + header.Length);
  3360. Array.Copy(header, 0, output, 4, header.Length);
  3361. Array.Copy(smbPacket, 0, output, 4 + header.Length, smbPacket.Length);
  3362. return output;
  3363. }
  3364. public static bool DoesServerSupportDialect(string server, string dialect)
  3365. {
  3366. Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect);
  3367. TcpClient client = new TcpClient();
  3368. try
  3369. {
  3370. client.Connect(server, 445);
  3371. }
  3372. catch (Exception)
  3373. {
  3374. throw new Exception("port 445 is closed on " + server);
  3375. }
  3376. try
  3377. {
  3378. NetworkStream stream = client.GetStream();
  3379. byte[] header = GenerateSmbHeaderFromCommand(SMB_COM_NEGOTIATE);
  3380. byte[] dialectEncoding = getDialect(dialect);
  3381. byte[] negotiatemessage = GetNegotiateMessage(dialectEncoding);
  3382. byte[] packet = GetNegotiatePacket(header, negotiatemessage);
  3383. stream.Write(packet, 0, packet.Length);
  3384. stream.Flush();
  3385. byte[] netbios = new byte[4];
  3386. if (stream.Read(netbios, 0, netbios.Length) != netbios.Length)
  3387. {
  3388. return false;
  3389. }
  3390. byte[] smbHeader = new byte[Marshal.SizeOf(typeof(SMB_Header))];
  3391. if (stream.Read(smbHeader, 0, smbHeader.Length) != smbHeader.Length)
  3392. {
  3393. return false;
  3394. }
  3395. byte[] negotiateresponse = new byte[3];
  3396. if (stream.Read(negotiateresponse, 0, negotiateresponse.Length) != negotiateresponse.Length)
  3397. {
  3398. return false;
  3399. }
  3400. if (negotiateresponse[1] == 0 && negotiateresponse[2] == 0)
  3401. {
  3402. Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect + " = Supported");
  3403. return true;
  3404. }
  3405. Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect + " = Not supported");
  3406. return false;
  3407. }
  3408. catch (Exception)
  3409. {
  3410. throw new ApplicationException("Smb1 is not supported on " + server);
  3411. }
  3412. }
  3413. public static bool DoesServerSupportDialectWithSmbV2(string server, int dialect, bool checkSMBSigning)
  3414. {
  3415. Trace.WriteLine("Checking " + server + " for SMBV2 dialect 0x" + dialect.ToString("X2"));
  3416. TcpClient client = new TcpClient();
  3417. try
  3418. {
  3419. client.Connect(server, 445);
  3420. }
  3421. catch (Exception)
  3422. {
  3423. throw new Exception("port 445 is closed on " + server);
  3424. }
  3425. try
  3426. {
  3427. NetworkStream stream = client.GetStream();
  3428. byte[] header = GenerateSmb2HeaderFromCommand(SMB2_NEGOTIATE);
  3429. byte[] negotiatemessage = GetNegotiateMessageSmbv2(dialect);
  3430. byte[] packet = GetNegotiatePacket(header, negotiatemessage);
  3431. stream.Write(packet, 0, packet.Length);
  3432. stream.Flush();
  3433. byte[] netbios = new byte[4];
  3434. if( stream.Read(netbios, 0, netbios.Length) != netbios.Length)
  3435. {
  3436. return false;
  3437. }
  3438. byte[] smbHeader = new byte[Marshal.SizeOf(typeof(SMB2_Header))];
  3439. if (stream.Read(smbHeader, 0, smbHeader.Length) != smbHeader.Length)
  3440. {
  3441. return false;
  3442. }
  3443. if (smbHeader[8] != 0 || smbHeader[9] != 0 || smbHeader[10] != 0 || smbHeader[11] != 0)
  3444. {
  3445. Trace.WriteLine("Checking " + server + " for SMBV2 dialect 0x" + dialect.ToString("X2") + " = Not supported via error code");
  3446. return false;
  3447. }
  3448. byte[] negotiateresponse = new byte[6];
  3449. if (stream.Read(negotiateresponse, 0, negotiateresponse.Length) != negotiateresponse.Length)
  3450. {
  3451. return false;
  3452. }
  3453. if (checkSMBSigning)
  3454. {
  3455. // https://support.microsoft.com/en-in/help/887429/overview-of-server-message-block-signing
  3456. // https://msdn.microsoft.com/en-us/library/cc246561.aspx
  3457. if (negotiateresponse[2] == 3)
  3458. {
  3459. Trace.WriteLine("Checking " + server + " for SMBV2 SMB Signing dialect 0x" + dialect.ToString("X2") + " = Supported");
  3460. return true;
  3461. }
  3462. else
  3463. {
  3464. return false;
  3465. }
  3466. }
  3467. int selectedDialect = negotiateresponse[5] * 0x100 + negotiateresponse[4];
  3468. if (selectedDialect == dialect)
  3469. {
  3470. Trace.WriteLine("Checking " + server + " for SMBV2 dialect 0x" + dialect.ToString("X2") + " = Supported");
  3471. return true;
  3472. }
  3473. Trace.WriteLine("Checking " + server + " for SMBV2 dialect 0x" + dialect.ToString("X2") + " = Not supported via not returned dialect");
  3474. return false;
  3475. }
  3476. catch (Exception)
  3477. {
  3478. throw new ApplicationException("Smb2 is not supported on " + server);
  3479. }
  3480. }
  3481. public static bool SupportSMB1(string server)
  3482. {
  3483. try
  3484. {
  3485. return DoesServerSupportDialect(server, "NT LM 0.12");
  3486. }
  3487. catch (Exception)
  3488. {
  3489. return false;
  3490. }
  3491. }
  3492. public static bool SupportSMB2(string server)
  3493. {
  3494. try
  3495. {
  3496. return (DoesServerSupportDialectWithSmbV2(server, 0x0202, false) || DoesServerSupportDialectWithSmbV2(server, 0x0210, false));
  3497. }
  3498. catch (Exception)
  3499. {
  3500. return false;
  3501. }
  3502. }
  3503. public static bool SupportSMB3(string server)
  3504. {
  3505. try
  3506. {
  3507. return (DoesServerSupportDialectWithSmbV2(server, 0x0300, false) || DoesServerSupportDialectWithSmbV2(server, 0x0302, false) || DoesServerSupportDialectWithSmbV2(server, 0x0311, false));
  3508. }
  3509. catch (Exception)
  3510. {
  3511. return false;
  3512. }
  3513. }
  3514. public static string Name { get { return "smb"; } }
  3515. public static PSObject GetPSObject(string computer)
  3516. {
  3517. PSObject DCSMBObj = new PSObject();
  3518. if (computer == "")
  3519. {
  3520. DCSMBObj.Members.Add(new PSNoteProperty("SMB Port Open", null));
  3521. DCSMBObj.Members.Add(new PSNoteProperty("SMB1(NT LM 0.12)", null));
  3522. DCSMBObj.Members.Add(new PSNoteProperty("SMB2(0x0202)", null));
  3523. DCSMBObj.Members.Add(new PSNoteProperty("SMB2(0x0210)", null));
  3524. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0300)", null));
  3525. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0302)", null));
  3526. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0311)", null));
  3527. DCSMBObj.Members.Add(new PSNoteProperty("SMB Signing", null));
  3528. return DCSMBObj;
  3529. }
  3530. bool isPortOpened = true;
  3531. bool SMBv1 = false;
  3532. bool SMBv2_0x0202 = false;
  3533. bool SMBv2_0x0210 = false;
  3534. bool SMBv3_0x0300 = false;
  3535. bool SMBv3_0x0302 = false;
  3536. bool SMBv3_0x0311 = false;
  3537. bool SMBSigning = false;
  3538. try
  3539. {
  3540. try
  3541. {
  3542. SMBv1 = DoesServerSupportDialect(computer, "NT LM 0.12");
  3543. }
  3544. catch (ApplicationException)
  3545. {
  3546. }
  3547. try
  3548. {
  3549. SMBv2_0x0202 = DoesServerSupportDialectWithSmbV2(computer, 0x0202, false);
  3550. SMBv2_0x0210 = DoesServerSupportDialectWithSmbV2(computer, 0x0210, false);
  3551. SMBv3_0x0300 = DoesServerSupportDialectWithSmbV2(computer, 0x0300, false);
  3552. SMBv3_0x0302 = DoesServerSupportDialectWithSmbV2(computer, 0x0302, false);
  3553. SMBv3_0x0311 = DoesServerSupportDialectWithSmbV2(computer, 0x0311, false);
  3554. }
  3555. catch (ApplicationException)
  3556. {
  3557. }
  3558. }
  3559. catch (Exception)
  3560. {
  3561. isPortOpened = false;
  3562. }
  3563. if (SMBv3_0x0311)
  3564. {
  3565. SMBSigning = DoesServerSupportDialectWithSmbV2(computer, 0x0311, true);
  3566. }
  3567. else if (SMBv3_0x0302)
  3568. {
  3569. SMBSigning = DoesServerSupportDialectWithSmbV2(computer, 0x0302, true);
  3570. }
  3571. else if (SMBv3_0x0300)
  3572. {
  3573. SMBSigning = DoesServerSupportDialectWithSmbV2(computer, 0x0300, true);
  3574. }
  3575. else if (SMBv2_0x0210)
  3576. {
  3577. SMBSigning = DoesServerSupportDialectWithSmbV2(computer, 0x0210, true);
  3578. }
  3579. else if (SMBv2_0x0202)
  3580. {
  3581. SMBSigning = DoesServerSupportDialectWithSmbV2(computer, 0x0202, true);
  3582. }
  3583. DCSMBObj.Members.Add(new PSNoteProperty("SMB Port Open", isPortOpened));
  3584. DCSMBObj.Members.Add(new PSNoteProperty("SMB1(NT LM 0.12)", SMBv1));
  3585. DCSMBObj.Members.Add(new PSNoteProperty("SMB2(0x0202)", SMBv2_0x0202));
  3586. DCSMBObj.Members.Add(new PSNoteProperty("SMB2(0x0210)", SMBv2_0x0210));
  3587. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0300)", SMBv3_0x0300));
  3588. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0302)", SMBv3_0x0302));
  3589. DCSMBObj.Members.Add(new PSNoteProperty("SMB3(0x0311)", SMBv3_0x0311));
  3590. DCSMBObj.Members.Add(new PSNoteProperty("SMB Signing", SMBSigning));
  3591. return DCSMBObj;
  3592. }
  3593. }
  3594. }
  3595. "@
  3596.  
  3597. # Import the LogonUser, ImpersonateLoggedOnUser and RevertToSelf Functions from advapi32.dll and the CloseHandle Function from kernel32.dll
  3598. # https://docs.microsoft.com/en-gb/powershell/module/Microsoft.PowerShell.Utility/Add-Type?view=powershell-5.1
  3599. # https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx
  3600. # https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx
  3601. # https://msdn.microsoft.com/en-us/library/windows/desktop/aa379317(v=vs.85).aspx
  3602.  
  3603. $Advapi32Def = @'
  3604. [DllImport("advapi32.dll", SetLastError = true)]
  3605. public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
  3606.  
  3607. [DllImport("advapi32.dll", SetLastError = true)]
  3608. public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
  3609.  
  3610. [DllImport("advapi32.dll", SetLastError = true)]
  3611. public static extern bool RevertToSelf();
  3612. '@
  3613.  
  3614. # https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
  3615.  
  3616. $Kernel32Def = @'
  3617. [DllImport("kernel32.dll", SetLastError = true)]
  3618. public static extern bool CloseHandle(IntPtr hObject);
  3619. '@
  3620.  
  3621. Function Get-DateDiff
  3622. {
  3623. <#
  3624. .SYNOPSIS
  3625. Get difference between two dates.
  3626.  
  3627. .DESCRIPTION
  3628. Returns the difference between two dates.
  3629.  
  3630. .PARAMETER Date1
  3631. [DateTime]
  3632. Date
  3633.  
  3634. .PARAMETER Date2
  3635. [DateTime]
  3636. Date
  3637.  
  3638. .OUTPUTS
  3639. [System.ValueType.TimeSpan]
  3640. Returns the difference between the two dates.
  3641. #>
  3642. param (
  3643. [Parameter(Mandatory = $true)]
  3644. [DateTime] $Date1,
  3645.  
  3646. [Parameter(Mandatory = $true)]
  3647. [DateTime] $Date2
  3648. )
  3649.  
  3650. If ($Date2 -gt $Date1)
  3651. {
  3652. $DDiff = $Date2 - $Date1
  3653. }
  3654. Else
  3655. {
  3656. $DDiff = $Date1 - $Date2
  3657. }
  3658. Return $DDiff
  3659. }
  3660.  
  3661. Function Get-DNtoFQDN
  3662. {
  3663. <#
  3664. .SYNOPSIS
  3665. Gets Domain Distinguished Name (DN) from the Fully Qualified Domain Name (FQDN).
  3666.  
  3667. .DESCRIPTION
  3668. Converts Domain Distinguished Name (DN) to Fully Qualified Domain Name (FQDN).
  3669.  
  3670. .PARAMETER ADObjectDN
  3671. [string]
  3672. Domain Distinguished Name (DN)
  3673.  
  3674. .OUTPUTS
  3675. [String]
  3676. Returns the Fully Qualified Domain Name (FQDN).
  3677.  
  3678. .LINK
  3679. https://adsecurity.org/?p=440
  3680. #>
  3681. param(
  3682. [Parameter(Mandatory = $true)]
  3683. [string] $ADObjectDN
  3684. )
  3685.  
  3686. $Index = $ADObjectDN.IndexOf('DC=')
  3687. If ($Index)
  3688. {
  3689. $ADObjectDNDomainName = $($ADObjectDN.SubString($Index)) -replace 'DC=','' -replace ',','.'
  3690. }
  3691. Else
  3692. {
  3693. # Modified version from https://adsecurity.org/?p=440
  3694. [array] $ADObjectDNArray = $ADObjectDN -Split ("DC=")
  3695. $ADObjectDNArray | ForEach-Object {
  3696. [array] $temp = $_ -Split (",")
  3697. [string] $ADObjectDNArrayItemDomainName += $temp[0] + "."
  3698. }
  3699. $ADObjectDNDomainName = $ADObjectDNArrayItemDomainName.Substring(1, $ADObjectDNArrayItemDomainName.Length - 2)
  3700. }
  3701. Return $ADObjectDNDomainName
  3702. }
  3703.  
  3704. Function Export-ADRCSV
  3705. {
  3706. <#
  3707. .SYNOPSIS
  3708. Exports Object to a CSV file.
  3709.  
  3710. .DESCRIPTION
  3711. Exports Object to a CSV file using Export-CSV.
  3712.  
  3713. .PARAMETER ADRObj
  3714. [PSObject]
  3715. ADRObj
  3716.  
  3717. .PARAMETER ADFileName
  3718. [String]
  3719. Path to save the CSV File.
  3720.  
  3721. .OUTPUTS
  3722. CSV file.
  3723. #>
  3724. param(
  3725. [Parameter(Mandatory = $true)]
  3726. [ValidateNotNullOrEmpty()]
  3727. [PSObject] $ADRObj,
  3728.  
  3729. [Parameter(Mandatory = $true)]
  3730. [ValidateNotNullOrEmpty()]
  3731. [String] $ADFileName
  3732. )
  3733.  
  3734. Try
  3735. {
  3736. $ADRObj | Export-Csv -Path $ADFileName -NoTypeInformation
  3737. }
  3738. Catch
  3739. {
  3740. Write-Warning "[Export-ADRCSV] Failed to export $($ADFileName)."
  3741. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  3742. }
  3743. }
  3744.  
  3745. Function Export-ADRXML
  3746. {
  3747. <#
  3748. .SYNOPSIS
  3749. Exports Object to a XML file.
  3750.  
  3751. .DESCRIPTION
  3752. Exports Object to a XML file using Export-Clixml.
  3753.  
  3754. .PARAMETER ADRObj
  3755. [PSObject]
  3756. ADRObj
  3757.  
  3758. .PARAMETER ADFileName
  3759. [String]
  3760. Path to save the XML File.
  3761.  
  3762. .OUTPUTS
  3763. XML file.
  3764. #>
  3765. param(
  3766. [Parameter(Mandatory = $true)]
  3767. [ValidateNotNullOrEmpty()]
  3768. [PSObject] $ADRObj,
  3769.  
  3770. [Parameter(Mandatory = $true)]
  3771. [ValidateNotNullOrEmpty()]
  3772. [String] $ADFileName
  3773. )
  3774.  
  3775. Try
  3776. {
  3777. (ConvertTo-Xml -NoTypeInformation -InputObject $ADRObj).Save($ADFileName)
  3778. }
  3779. Catch
  3780. {
  3781. Write-Warning "[Export-ADRXML] Failed to export $($ADFileName)."
  3782. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  3783. }
  3784. }
  3785.  
  3786. Function Export-ADRJSON
  3787. {
  3788. <#
  3789. .SYNOPSIS
  3790. Exports Object to a JSON file.
  3791.  
  3792. .DESCRIPTION
  3793. Exports Object to a JSON file using ConvertTo-Json.
  3794.  
  3795. .PARAMETER ADRObj
  3796. [PSObject]
  3797. ADRObj
  3798.  
  3799. .PARAMETER ADFileName
  3800. [String]
  3801. Path to save the JSON File.
  3802.  
  3803. .OUTPUTS
  3804. JSON file.
  3805. #>
  3806. param(
  3807. [Parameter(Mandatory = $true)]
  3808. [ValidateNotNullOrEmpty()]
  3809. [PSObject] $ADRObj,
  3810.  
  3811. [Parameter(Mandatory = $true)]
  3812. [ValidateNotNullOrEmpty()]
  3813. [String] $ADFileName
  3814. )
  3815.  
  3816. Try
  3817. {
  3818. ConvertTo-JSON -InputObject $ADRObj | Out-File -FilePath $ADFileName
  3819. }
  3820. Catch
  3821. {
  3822. Write-Warning "[Export-ADRJSON] Failed to export $($ADFileName)."
  3823. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  3824. }
  3825. }
  3826.  
  3827. Function Export-ADRHTML
  3828. {
  3829. <#
  3830. .SYNOPSIS
  3831. Exports Object to a HTML file.
  3832.  
  3833. .DESCRIPTION
  3834. Exports Object to a HTML file using ConvertTo-Html.
  3835.  
  3836. .PARAMETER ADRObj
  3837. [PSObject]
  3838. ADRObj
  3839.  
  3840. .PARAMETER ADFileName
  3841. [String]
  3842. Path to save the HTML File.
  3843.  
  3844. .OUTPUTS
  3845. HTML file.
  3846. #>
  3847. param(
  3848. [Parameter(Mandatory = $true)]
  3849. [ValidateNotNullOrEmpty()]
  3850. [PSObject] $ADRObj,
  3851.  
  3852. [Parameter(Mandatory = $true)]
  3853. [ValidateNotNullOrEmpty()]
  3854. [String] $ADFileName,
  3855.  
  3856. [Parameter(Mandatory = $false)]
  3857. [String] $ADROutputDir = $null
  3858. )
  3859.  
  3860. $Header = @"
  3861. <style type="text/css">
  3862. th {
  3863. color:white;
  3864. background-color:blue;
  3865. }
  3866. td, th {
  3867. border:0px solid black;
  3868. border-collapse:collapse;
  3869. white-space:pre;
  3870. }
  3871. tr:nth-child(2n+1) {
  3872. background-color: #dddddd;
  3873. }
  3874. tr:hover td {
  3875. background-color: #c1d5f8;
  3876. }
  3877. table, tr, td, th {
  3878. padding: 0px;
  3879. margin: 0px;
  3880. white-space:pre;
  3881. }
  3882. table {
  3883. margin-left:1px;
  3884. }
  3885. </style>
  3886. "@
  3887. Try
  3888. {
  3889. If ($ADFileName.Contains("Index"))
  3890. {
  3891. $HTMLPath = -join($ADROutputDir,'\','HTML-Files')
  3892. $HTMLPath = $((Convert-Path $HTMLPath).TrimEnd("\"))
  3893. $HTMLFiles = Get-ChildItem -Path $HTMLPath -name
  3894. $HTML = $HTMLFiles | ConvertTo-HTML -Title "ADRecon" -Property @{Label="Table of Contents";Expression={"<a href='$($_)'>$($_)</a>"}} -Head $Header
  3895.  
  3896. Add-Type -AssemblyName System.Web
  3897. [System.Web.HttpUtility]::HtmlDecode($HTML) | Out-File -FilePath $ADFileName
  3898. }
  3899. Else
  3900. {
  3901. If ($ADRObj -is [array])
  3902. {
  3903. $ADRObj | Select-Object * | ConvertTo-HTML -As Table -Head $Header | Out-File -FilePath $ADFileName
  3904. }
  3905. Else
  3906. {
  3907. ConvertTo-HTML -InputObject $ADRObj -As Table -Head $Header | Out-File -FilePath $ADFileName
  3908. }
  3909. }
  3910. }
  3911. Catch
  3912. {
  3913. Write-Warning "[Export-ADRHTML] Failed to export $($ADFileName)."
  3914. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  3915. }
  3916. }
  3917.  
  3918. Function Export-ADR
  3919. {
  3920. <#
  3921. .SYNOPSIS
  3922. Helper function for all output types supported.
  3923.  
  3924. .DESCRIPTION
  3925. Helper function for all output types supported.
  3926.  
  3927. .PARAMETER ADObjectDN
  3928. [PSObject]
  3929. ADRObj
  3930.  
  3931. .PARAMETER ADROutputDir
  3932. [String]
  3933. Path for ADRecon output folder.
  3934.  
  3935. .PARAMETER OutputType
  3936. [array]
  3937. Output Type.
  3938.  
  3939. .PARAMETER ADRModuleName
  3940. [String]
  3941. Module Name.
  3942.  
  3943. .OUTPUTS
  3944. STDOUT, CSV, XML, JSON and/or HTML file, etc.
  3945. #>
  3946. param(
  3947. [Parameter(Mandatory = $true)]
  3948. [PSObject] $ADRObj,
  3949.  
  3950. [Parameter(Mandatory = $true)]
  3951. [String] $ADROutputDir,
  3952.  
  3953. [Parameter(Mandatory = $true)]
  3954. [array] $OutputType,
  3955.  
  3956. [Parameter(Mandatory = $true)]
  3957. [String] $ADRModuleName
  3958. )
  3959.  
  3960. Switch ($OutputType)
  3961. {
  3962. 'STDOUT'
  3963. {
  3964. If ($ADRModuleName -ne "AboutADRecon")
  3965. {
  3966. If ($ADRObj -is [array])
  3967. {
  3968. # Fix for InvalidOperationException: The object of type "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" is not valid or not in the correct sequence.
  3969. $ADRObj | Out-String -Stream
  3970. }
  3971. Else
  3972. {
  3973. # Fix for InvalidOperationException: The object of type "Microsoft.PowerShell.Commands.Internal.Format.FormatStartData" is not valid or not in the correct sequence.
  3974. $ADRObj | Format-List | Out-String -Stream
  3975. }
  3976. }
  3977. }
  3978. 'CSV'
  3979. {
  3980. $ADFileName = -join($ADROutputDir,'\','CSV-Files','\',$ADRModuleName,'.csv')
  3981. Export-ADRCSV -ADRObj $ADRObj -ADFileName $ADFileName
  3982. }
  3983. 'XML'
  3984. {
  3985. $ADFileName = -join($ADROutputDir,'\','XML-Files','\',$ADRModuleName,'.xml')
  3986. Export-ADRXML -ADRObj $ADRObj -ADFileName $ADFileName
  3987. }
  3988. 'JSON'
  3989. {
  3990. $ADFileName = -join($ADROutputDir,'\','JSON-Files','\',$ADRModuleName,'.json')
  3991. Export-ADRJSON -ADRObj $ADRObj -ADFileName $ADFileName
  3992. }
  3993. 'HTML'
  3994. {
  3995. $ADFileName = -join($ADROutputDir,'\','HTML-Files','\',$ADRModuleName,'.html')
  3996. Export-ADRHTML -ADRObj $ADRObj -ADFileName $ADFileName -ADROutputDir $ADROutputDir
  3997. }
  3998. }
  3999. }
  4000.  
  4001. Function Get-ADRExcelComObj
  4002. {
  4003. <#
  4004. .SYNOPSIS
  4005. Creates a ComObject to interact with Microsoft Excel.
  4006.  
  4007. .DESCRIPTION
  4008. Creates a ComObject to interact with Microsoft Excel if installed, else warning is raised.
  4009.  
  4010. .OUTPUTS
  4011. [System.__ComObject] and [System.MarshalByRefObject]
  4012. Creates global variables $excel and $workbook.
  4013. #>
  4014.  
  4015. #Check if Excel is installed.
  4016. Try
  4017. {
  4018. # Suppress verbose output
  4019. $SaveVerbosePreference = $script:VerbosePreference
  4020. $script:VerbosePreference = 'SilentlyContinue'
  4021. $global:excel = New-Object -ComObject excel.application
  4022. If ($SaveVerbosePreference)
  4023. {
  4024. $script:VerbosePreference = $SaveVerbosePreference
  4025. Remove-Variable SaveVerbosePreference
  4026. }
  4027. }
  4028. Catch
  4029. {
  4030. If ($SaveVerbosePreference)
  4031. {
  4032. $script:VerbosePreference = $SaveVerbosePreference
  4033. Remove-Variable SaveVerbosePreference
  4034. }
  4035. Write-Warning "[Get-ADRExcelComObj] Excel does not appear to be installed. Skipping generation of ADRecon-Report.xlsx. Use the -GenExcel parameter to generate the ADRecon-Report.xslx on a host with Microsoft Excel installed."
  4036. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  4037. Return $null
  4038. }
  4039. $excel.Visible = $true
  4040. $excel.Interactive = $false
  4041. $global:workbook = $excel.Workbooks.Add()
  4042. If ($workbook.Worksheets.Count -eq 3)
  4043. {
  4044. $workbook.WorkSheets.Item(3).Delete()
  4045. $workbook.WorkSheets.Item(2).Delete()
  4046. }
  4047. }
  4048.  
  4049. Function Get-ADRExcelComObjRelease
  4050. {
  4051. <#
  4052. .SYNOPSIS
  4053. Releases the ComObject created to interact with Microsoft Excel.
  4054.  
  4055. .DESCRIPTION
  4056. Releases the ComObject created to interact with Microsoft Excel.
  4057.  
  4058. .PARAMETER ComObjtoRelease
  4059. ComObjtoRelease
  4060.  
  4061. .PARAMETER Final
  4062. Final
  4063. #>
  4064. param(
  4065. [Parameter(Mandatory = $true)]
  4066. $ComObjtoRelease,
  4067.  
  4068. [Parameter(Mandatory = $false)]
  4069. [bool] $Final = $false
  4070. )
  4071. # https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject(v=vs.110).aspx
  4072. # https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.finalreleasecomobject(v=vs.110).aspx
  4073. If ($Final)
  4074. {
  4075. [System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($ComObjtoRelease) | Out-Null
  4076. }
  4077. Else
  4078. {
  4079. [System.Runtime.InteropServices.Marshal]::ReleaseComObject($ComObjtoRelease) | Out-Null
  4080. }
  4081. [System.GC]::Collect()
  4082. [System.GC]::WaitForPendingFinalizers()
  4083. }
  4084.  
  4085. Function Get-ADRExcelWorkbook
  4086. {
  4087. <#
  4088. .SYNOPSIS
  4089. Adds a WorkSheet to the Workbook.
  4090.  
  4091. .DESCRIPTION
  4092. Adds a WorkSheet to the Workbook using the $workboook global variable and assigns it a name.
  4093.  
  4094. .PARAMETER name
  4095. [string]
  4096. Name of the WorkSheet.
  4097. #>
  4098. param (
  4099. [Parameter(Mandatory = $true)]
  4100. [string] $name
  4101. )
  4102.  
  4103. $workbook.Worksheets.Add() | Out-Null
  4104. $worksheet = $workbook.Worksheets.Item(1)
  4105. $worksheet.Name = $name
  4106.  
  4107. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4108. Remove-Variable worksheet
  4109. }
  4110.  
  4111. Function Get-ADRExcelImport
  4112. {
  4113. <#
  4114. .SYNOPSIS
  4115. Helper to import CSV to the current WorkSheet.
  4116.  
  4117. .DESCRIPTION
  4118. Helper to import CSV to the current WorkSheet. Supports two methods.
  4119.  
  4120. .PARAMETER ADFileName
  4121. [string]
  4122. Filename of the CSV file to import.
  4123.  
  4124. .PARAMETER method
  4125. [int]
  4126. Method to use for the import.
  4127.  
  4128. .PARAMETER row
  4129. [int]
  4130. Row.
  4131.  
  4132. .PARAMETER column
  4133. [int]
  4134. Column.
  4135. #>
  4136. param (
  4137. [Parameter(Mandatory = $true)]
  4138. [string] $ADFileName,
  4139.  
  4140. [Parameter(Mandatory = $false)]
  4141. [int] $method = 1,
  4142.  
  4143. [Parameter(Mandatory = $false)]
  4144. [int] $row = 1,
  4145.  
  4146. [Parameter(Mandatory = $false)]
  4147. [int] $column = 1
  4148. )
  4149.  
  4150. $excel.ScreenUpdating = $false
  4151. If ($method -eq 1)
  4152. {
  4153. If (Test-Path $ADFileName)
  4154. {
  4155. $worksheet = $workbook.Worksheets.Item(1)
  4156. $TxtConnector = ("TEXT;" + $ADFileName)
  4157. $CellRef = $worksheet.Range("A1")
  4158. #Build, use and remove the text file connector
  4159. $Connector = $worksheet.QueryTables.add($TxtConnector, $CellRef)
  4160.  
  4161. #65001: Unicode (UTF-8)
  4162. $worksheet.QueryTables.item($Connector.name).TextFilePlatform = 65001
  4163. $worksheet.QueryTables.item($Connector.name).TextFileCommaDelimiter = $True
  4164. $worksheet.QueryTables.item($Connector.name).TextFileParseType = 1
  4165. $worksheet.QueryTables.item($Connector.name).Refresh() | Out-Null
  4166. $worksheet.QueryTables.item($Connector.name).delete()
  4167.  
  4168. Get-ADRExcelComObjRelease -ComObjtoRelease $CellRef
  4169. Remove-Variable CellRef
  4170. Get-ADRExcelComObjRelease -ComObjtoRelease $Connector
  4171. Remove-Variable Connector
  4172.  
  4173. $listObject = $worksheet.ListObjects.Add([Microsoft.Office.Interop.Excel.XlListObjectSourceType]::xlSrcRange, $worksheet.UsedRange, $null, [Microsoft.Office.Interop.Excel.XlYesNoGuess]::xlYes, $null)
  4174. $listObject.TableStyle = "TableStyleLight2" # Style Cheat Sheet: https://msdn.microsoft.com/en-au/library/documentformat.openxml.spreadsheet.tablestyle.aspx
  4175. $worksheet.UsedRange.EntireColumn.AutoFit() | Out-Null
  4176. }
  4177. Remove-Variable ADFileName
  4178. }
  4179. Elseif ($method -eq 2)
  4180. {
  4181. $worksheet = $workbook.Worksheets.Item(1)
  4182. If (Test-Path $ADFileName)
  4183. {
  4184. $ADTemp = Import-Csv -Path $ADFileName
  4185. $ADTemp | ForEach-Object {
  4186. Foreach ($prop in $_.PSObject.Properties)
  4187. {
  4188. $worksheet.Cells.Item($row, $column) = $prop.Name
  4189. $worksheet.Cells.Item($row, $column + 1) = $prop.Value
  4190. $row++
  4191. }
  4192. }
  4193. Remove-Variable ADTemp
  4194. $listObject = $worksheet.ListObjects.Add([Microsoft.Office.Interop.Excel.XlListObjectSourceType]::xlSrcRange, $worksheet.UsedRange, $null, [Microsoft.Office.Interop.Excel.XlYesNoGuess]::xlYes, $null)
  4195. $listObject.TableStyle = "TableStyleLight2" # Style Cheat Sheet: https://msdn.microsoft.com/en-au/library/documentformat.openxml.spreadsheet.tablestyle.aspx
  4196. $usedRange = $worksheet.UsedRange
  4197. $usedRange.EntireColumn.AutoFit() | Out-Null
  4198. }
  4199. Else
  4200. {
  4201. $worksheet.Cells.Item($row, $column) = "Error!"
  4202. }
  4203. Remove-Variable ADFileName
  4204. }
  4205. $excel.ScreenUpdating = $true
  4206.  
  4207. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4208. Remove-Variable worksheet
  4209. }
  4210.  
  4211. # Thanks Anant Shrivastava for the suggestion of using Pivot Tables for generation of the Stats sheets.
  4212. Function Get-ADRExcelPivotTable
  4213. {
  4214. <#
  4215. .SYNOPSIS
  4216. Helper to add Pivot Table to the current WorkSheet.
  4217.  
  4218. .DESCRIPTION
  4219. Helper to add Pivot Table to the current WorkSheet.
  4220.  
  4221. .PARAMETER SrcSheetName
  4222. [string]
  4223. Source Sheet Name.
  4224.  
  4225. .PARAMETER PivotTableName
  4226. [string]
  4227. Pivot Table Name.
  4228.  
  4229. .PARAMETER PivotRows
  4230. [array]
  4231. Row names from Source Sheet.
  4232.  
  4233. .PARAMETER PivotColumns
  4234. [array]
  4235. Column names from Source Sheet.
  4236.  
  4237. .PARAMETER PivotFilters
  4238. [array]
  4239. Row/Column names from Source Sheet to use as filters.
  4240.  
  4241. .PARAMETER PivotValues
  4242. [array]
  4243. Row/Column names from Source Sheet to use for Values.
  4244.  
  4245. .PARAMETER PivotPercentage
  4246. [array]
  4247. Row/Column names from Source Sheet to use for Percentage.
  4248.  
  4249. .PARAMETER PivotLocation
  4250. [array]
  4251. Location of the Pivot Table in Row/Column.
  4252. #>
  4253. param (
  4254. [Parameter(Mandatory = $true)]
  4255. [string] $SrcSheetName,
  4256.  
  4257. [Parameter(Mandatory = $true)]
  4258. [string] $PivotTableName,
  4259.  
  4260. [Parameter(Mandatory = $false)]
  4261. [array] $PivotRows,
  4262.  
  4263. [Parameter(Mandatory = $false)]
  4264. [array] $PivotColumns,
  4265.  
  4266. [Parameter(Mandatory = $false)]
  4267. [array] $PivotFilters,
  4268.  
  4269. [Parameter(Mandatory = $false)]
  4270. [array] $PivotValues,
  4271.  
  4272. [Parameter(Mandatory = $false)]
  4273. [array] $PivotPercentage,
  4274.  
  4275. [Parameter(Mandatory = $false)]
  4276. [string] $PivotLocation = "R1C1"
  4277. )
  4278.  
  4279. $excel.ScreenUpdating = $false
  4280. $SrcWorksheet = $workbook.Sheets.Item($SrcSheetName)
  4281. $workbook.ShowPivotTableFieldList = $false
  4282.  
  4283. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlpivottablesourcetype-enumeration-excel
  4284. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlpivottableversionlist-enumeration-excel
  4285. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlpivotfieldorientation-enumeration-excel
  4286. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/constants-enumeration-excel
  4287. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlsortorder-enumeration-excel
  4288. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlpivotfiltertype-enumeration-excel
  4289.  
  4290. # xlDatabase = 1 # this just means local sheet data
  4291. # xlPivotTableVersion12 = 3 # Excel 2007
  4292. $PivotFailed = $false
  4293. Try
  4294. {
  4295. $PivotCaches = $workbook.PivotCaches().Create([Microsoft.Office.Interop.Excel.XlPivotTableSourceType]::xlDatabase, $SrcWorksheet.UsedRange, [Microsoft.Office.Interop.Excel.XlPivotTableVersionList]::xlPivotTableVersion12)
  4296. }
  4297. Catch
  4298. {
  4299. $PivotFailed = $true
  4300. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  4301. }
  4302. If ( $PivotFailed -eq $true )
  4303. {
  4304. $rows = $SrcWorksheet.UsedRange.Rows.Count
  4305. If ($SrcSheetName -eq "Computer SPNs")
  4306. {
  4307. $PivotCols = "A1:B"
  4308. }
  4309. ElseIf ($SrcSheetName -eq "Users")
  4310. {
  4311. $PivotCols = "A1:AI"
  4312. }
  4313. $UsedRange = $SrcWorksheet.Range($PivotCols+$rows)
  4314. $PivotCaches = $workbook.PivotCaches().Create([Microsoft.Office.Interop.Excel.XlPivotTableSourceType]::xlDatabase, $UsedRange, [Microsoft.Office.Interop.Excel.XlPivotTableVersionList]::xlPivotTableVersion12)
  4315. Remove-Variable rows
  4316. Remove-Variable PivotCols
  4317. Remove-Variable UsedRange
  4318. }
  4319. Remove-Variable PivotFailed
  4320. $PivotTable = $PivotCaches.CreatePivotTable($PivotLocation,$PivotTableName)
  4321. # $workbook.ShowPivotTableFieldList = $true
  4322.  
  4323. If ($PivotRows)
  4324. {
  4325. ForEach ($Row in $PivotRows)
  4326. {
  4327. $PivotField = $PivotTable.PivotFields($Row)
  4328. $PivotField.Orientation = [Microsoft.Office.Interop.Excel.XlPivotFieldOrientation]::xlRowField
  4329. }
  4330. }
  4331.  
  4332. If ($PivotColumns)
  4333. {
  4334. ForEach ($Col in $PivotColumns)
  4335. {
  4336. $PivotField = $PivotTable.PivotFields($Col)
  4337. $PivotField.Orientation = [Microsoft.Office.Interop.Excel.XlPivotFieldOrientation]::xlColumnField
  4338. }
  4339. }
  4340.  
  4341. If ($PivotFilters)
  4342. {
  4343. ForEach ($Fil in $PivotFilters)
  4344. {
  4345. $PivotField = $PivotTable.PivotFields($Fil)
  4346. $PivotField.Orientation = [Microsoft.Office.Interop.Excel.XlPivotFieldOrientation]::xlPageField
  4347. }
  4348. }
  4349.  
  4350. If ($PivotValues)
  4351. {
  4352. ForEach ($Val in $PivotValues)
  4353. {
  4354. $PivotField = $PivotTable.PivotFields($Val)
  4355. $PivotField.Orientation = [Microsoft.Office.Interop.Excel.XlPivotFieldOrientation]::xlDataField
  4356. }
  4357. }
  4358.  
  4359. If ($PivotPercentage)
  4360. {
  4361. ForEach ($Val in $PivotPercentage)
  4362. {
  4363. $PivotField = $PivotTable.PivotFields($Val)
  4364. $PivotField.Orientation = [Microsoft.Office.Interop.Excel.XlPivotFieldOrientation]::xlDataField
  4365. $PivotField.Calculation = [Microsoft.Office.Interop.Excel.XlPivotFieldCalculation]::xlPercentOfTotal
  4366. $PivotTable.ShowValuesRow = $false
  4367. }
  4368. }
  4369.  
  4370. # $PivotFields.Caption = ""
  4371. $excel.ScreenUpdating = $true
  4372.  
  4373. Get-ADRExcelComObjRelease -ComObjtoRelease $PivotField
  4374. Remove-Variable PivotField
  4375. Get-ADRExcelComObjRelease -ComObjtoRelease $PivotTable
  4376. Remove-Variable PivotTable
  4377. Get-ADRExcelComObjRelease -ComObjtoRelease $PivotCaches
  4378. Remove-Variable PivotCaches
  4379. Get-ADRExcelComObjRelease -ComObjtoRelease $SrcWorksheet
  4380. Remove-Variable SrcWorksheet
  4381. }
  4382.  
  4383. Function Get-ADRExcelAttributeStats
  4384. {
  4385. <#
  4386. .SYNOPSIS
  4387. Helper to add Attribute Stats to the current WorkSheet.
  4388.  
  4389. .DESCRIPTION
  4390. Helper to add Attribute Stats to the current WorkSheet.
  4391.  
  4392. .PARAMETER SrcSheetName
  4393. [string]
  4394. Source Sheet Name.
  4395.  
  4396. .PARAMETER Title1
  4397. [string]
  4398. Title1.
  4399.  
  4400. .PARAMETER Title2
  4401. [string]
  4402. Title2.
  4403.  
  4404. .PARAMETER ObjAttributes
  4405. [OrderedDictionary]
  4406. Attributes.
  4407. #>
  4408. param (
  4409. [Parameter(Mandatory = $true)]
  4410. [string] $SrcSheetName,
  4411.  
  4412. [Parameter(Mandatory = $true)]
  4413. [string] $Title1,
  4414.  
  4415. [Parameter(Mandatory = $true)]
  4416. [string] $Title2,
  4417.  
  4418. [Parameter(Mandatory = $true)]
  4419. [System.Object] $ObjAttributes
  4420. )
  4421.  
  4422. $excel.ScreenUpdating = $false
  4423. $worksheet = $workbook.Worksheets.Item(1)
  4424. $SrcWorksheet = $workbook.Sheets.Item($SrcSheetName)
  4425.  
  4426. $row = 1
  4427. $column = 1
  4428. $worksheet.Cells.Item($row, $column) = $Title1
  4429. $worksheet.Cells.Item($row,$column).Style = "Heading 2"
  4430. $worksheet.Cells.Item($row,$column).HorizontalAlignment = -4108
  4431. $MergeCells = $worksheet.Range("A1:C1")
  4432. $MergeCells.Select() | Out-Null
  4433. $MergeCells.MergeCells = $true
  4434. Remove-Variable MergeCells
  4435.  
  4436. Get-ADRExcelPivotTable -SrcSheetName $SrcSheetName -PivotTableName "User Status" -PivotRows @("Enabled") -PivotValues @("UserName") -PivotPercentage @("UserName") -PivotLocation "R2C1"
  4437. $excel.ScreenUpdating = $false
  4438.  
  4439. $row = 2
  4440. "Type","Count","Percentage" | ForEach-Object {
  4441. $worksheet.Cells.Item($row, $column) = $_
  4442. $worksheet.Cells.Item($row, $column).Font.Bold = $True
  4443. $column++
  4444. }
  4445.  
  4446. $row = 3
  4447. $column = 1
  4448. For($row = 3; $row -le 6; $row++)
  4449. {
  4450. $temptext = [string] $worksheet.Cells.Item($row, $column).Text
  4451. switch ($temptext.ToUpper())
  4452. {
  4453. "TRUE" { $worksheet.Cells.Item($row, $column) = "Enabled" }
  4454. "FALSE" { $worksheet.Cells.Item($row, $column) = "Disabled" }
  4455. "GRAND TOTAL" { $worksheet.Cells.Item($row, $column) = "Total" }
  4456. }
  4457. }
  4458.  
  4459. $row = 1
  4460. $column = 6
  4461. $worksheet.Cells.Item($row, $column) = $Title2
  4462. $worksheet.Cells.Item($row,$column).Style = "Heading 2"
  4463. $worksheet.Cells.Item($row,$column).HorizontalAlignment = -4108
  4464. $MergeCells = $worksheet.Range("F1:L1")
  4465. $MergeCells.Select() | Out-Null
  4466. $MergeCells.MergeCells = $true
  4467. Remove-Variable MergeCells
  4468.  
  4469. $row++
  4470. "Category","Enabled Count","Enabled Percentage","Disabled Count","Disabled Percentage","Total Count","Total Percentage" | ForEach-Object {
  4471. $worksheet.Cells.Item($row, $column) = $_
  4472. $worksheet.Cells.Item($row, $column).Font.Bold = $True
  4473. $column++
  4474. }
  4475.  
  4476. $ExcelColumn = ($SrcWorksheet.Columns.Find("Enabled"))
  4477. $EnabledColAddress = "$($ExcelColumn.Address($false,$false).Substring(0,$ExcelColumn.Address($false,$false).Length-1)):$($ExcelColumn.Address($false,$false).Substring(0,$ExcelColumn.Address($false,$false).Length-1))"
  4478.  
  4479. $column = 6
  4480. $i = 2
  4481.  
  4482. $ObjAttributes.keys | ForEach-Object {
  4483. $ExcelColumn = ($SrcWorksheet.Columns.Find($_))
  4484. $ColAddress = "$($ExcelColumn.Address($false,$false).Substring(0,$ExcelColumn.Address($false,$false).Length-1)):$($ExcelColumn.Address($false,$false).Substring(0,$ExcelColumn.Address($false,$false).Length-1))"
  4485. $row++
  4486. $i++
  4487. If ($_ -eq "Delegation Typ")
  4488. {
  4489. $worksheet.Cells.Item($row, $column) = "Unconstrained Delegation"
  4490. }
  4491. ElseIf ($_ -eq "Delegation Type")
  4492. {
  4493. $worksheet.Cells.Item($row, $column) = "Constrained Delegation"
  4494. }
  4495. Else
  4496. {
  4497. $worksheet.Cells.Item($row, $column).Formula = '=' + $SrcWorksheet.Name + '!' + $ExcelColumn.Address($false,$false)
  4498. }
  4499. $worksheet.Cells.Item($row, $column+1).Formula = '=COUNTIFS(' + $SrcWorksheet.Name + '!' + $EnabledColAddress + ',"TRUE",' + $SrcWorksheet.Name + '!' + $ColAddress + ',' + $ObjAttributes[$_] + ')'
  4500. $worksheet.Cells.Item($row, $column+2).Formula = '=IFERROR(G' + $i + '/VLOOKUP("Enabled",A3:B6,2,FALSE),0)'
  4501. $worksheet.Cells.Item($row, $column+3).Formula = '=COUNTIFS(' + $SrcWorksheet.Name + '!' + $EnabledColAddress + ',"FALSE",' + $SrcWorksheet.Name + '!' + $ColAddress + ',' + $ObjAttributes[$_] + ')'
  4502. $worksheet.Cells.Item($row, $column+4).Formula = '=IFERROR(I' + $i + '/VLOOKUP("Disabled",A3:B6,2,FALSE),0)'
  4503. If ( ($_ -eq "SIDHistory") -or ($_ -eq "ms-ds-CreatorSid") )
  4504. {
  4505. $worksheet.Cells.Item($row, $column+5).Formula = '=COUNTIF(' + $SrcWorksheet.Name + '!' + $ColAddress + ',' + $ObjAttributes[$_] + ')-1'
  4506. }
  4507. Else
  4508. {
  4509. $worksheet.Cells.Item($row, $column+5).Formula = '=COUNTIF(' + $SrcWorksheet.Name + '!' + $ColAddress + ',' + $ObjAttributes[$_] + ')'
  4510. }
  4511. $worksheet.Cells.Item($row, $column+6).Formula = '=IFERROR(K' + $i + '/VLOOKUP("Total",A3:B6,2,FALSE),0)'
  4512. }
  4513.  
  4514. # http://www.excelhowto.com/macros/formatting-a-range-of-cells-in-excel-vba/
  4515. "H", "J" , "L" | ForEach-Object {
  4516. $rng = $_ + $($row - $ObjAttributes.Count + 1) + ":" + $_ + $($row)
  4517. $worksheet.Range($rng).NumberFormat = "0.00%"
  4518. }
  4519. $excel.ScreenUpdating = $true
  4520.  
  4521. Get-ADRExcelComObjRelease -ComObjtoRelease $SrcWorksheet
  4522. Remove-Variable SrcWorksheet
  4523. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4524. Remove-Variable worksheet
  4525. }
  4526.  
  4527. Function Get-ADRExcelChart
  4528. {
  4529. <#
  4530. .SYNOPSIS
  4531. Helper to add charts to the current WorkSheet.
  4532.  
  4533. .DESCRIPTION
  4534. Helper to add charts to the current WorkSheet.
  4535.  
  4536. .PARAMETER ChartType
  4537. [int]
  4538. Chart Type.
  4539.  
  4540. .PARAMETER ChartLayout
  4541. [int]
  4542. Chart Layout.
  4543.  
  4544. .PARAMETER ChartTitle
  4545. [string]
  4546. Title of the Chart.
  4547.  
  4548. .PARAMETER RangetoCover
  4549. WorkSheet Range to be covered by the Chart.
  4550.  
  4551. .PARAMETER ChartData
  4552. Data for the Chart.
  4553.  
  4554. .PARAMETER StartRow
  4555. Start row to calculate data for the Chart.
  4556.  
  4557. .PARAMETER StartColumn
  4558. Start column to calculate data for the Chart.
  4559. #>
  4560. param (
  4561. [Parameter(Mandatory = $true)]
  4562. [string] $ChartType,
  4563.  
  4564. [Parameter(Mandatory = $true)]
  4565. [int] $ChartLayout,
  4566.  
  4567. [Parameter(Mandatory = $true)]
  4568. [string] $ChartTitle,
  4569.  
  4570. [Parameter(Mandatory = $true)]
  4571. $RangetoCover,
  4572.  
  4573. [Parameter(Mandatory = $false)]
  4574. $ChartData = $null,
  4575.  
  4576. [Parameter(Mandatory = $false)]
  4577. $StartRow = $null,
  4578.  
  4579. [Parameter(Mandatory = $false)]
  4580. $StartColumn = $null
  4581. )
  4582.  
  4583. $excel.ScreenUpdating = $false
  4584. $excel.DisplayAlerts = $false
  4585. $worksheet = $workbook.Worksheets.Item(1)
  4586. $chart = $worksheet.Shapes.AddChart().Chart
  4587. # https://msdn.microsoft.com/en-us/vba/excel-vba/articles/xlcharttype-enumeration-excel
  4588. $chart.chartType = [int]([Microsoft.Office.Interop.Excel.XLChartType]::$ChartType)
  4589. $chart.ApplyLayout($ChartLayout)
  4590. If ($null -eq $ChartData)
  4591. {
  4592. If ($null -eq $StartRow)
  4593. {
  4594. $start = $worksheet.Range("A1")
  4595. }
  4596. Else
  4597. {
  4598. $start = $worksheet.Range($StartRow)
  4599. }
  4600. # get the last cell
  4601. $X = $worksheet.Range($start,$start.End([Microsoft.Office.Interop.Excel.XLDirection]::xlDown))
  4602. If ($null -eq $StartColumn)
  4603. {
  4604. $start = $worksheet.Range("B1")
  4605. }
  4606. Else
  4607. {
  4608. $start = $worksheet.Range($StartColumn)
  4609. }
  4610. # get the last cell
  4611. $Y = $worksheet.Range($start,$start.End([Microsoft.Office.Interop.Excel.XLDirection]::xlDown))
  4612. $ChartData = $worksheet.Range($X,$Y)
  4613.  
  4614. Get-ADRExcelComObjRelease -ComObjtoRelease $X
  4615. Remove-Variable X
  4616. Get-ADRExcelComObjRelease -ComObjtoRelease $Y
  4617. Remove-Variable Y
  4618. Get-ADRExcelComObjRelease -ComObjtoRelease $start
  4619. Remove-Variable start
  4620. }
  4621. $chart.SetSourceData($ChartData)
  4622. # https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.chartclass.plotby?redirectedfrom=MSDN&view=excel-pia#Microsoft_Office_Interop_Excel_ChartClass_PlotBy
  4623. $chart.PlotBy = [Microsoft.Office.Interop.Excel.XlRowCol]::xlColumns
  4624. $chart.seriesCollection(1).Select() | Out-Null
  4625. $chart.SeriesCollection(1).ApplyDataLabels() | out-Null
  4626. # modify the chart title
  4627. $chart.HasTitle = $True
  4628. $chart.ChartTitle.Text = $ChartTitle
  4629. # Reposition the Chart
  4630. $temp = $worksheet.Range($RangetoCover)
  4631. # $chart.parent.placement = 3
  4632. $chart.parent.top = $temp.Top
  4633. $chart.parent.left = $temp.Left
  4634. $chart.parent.width = $temp.Width
  4635. If ($ChartTitle -ne "Privileged Groups in AD")
  4636. {
  4637. $chart.parent.height = $temp.Height
  4638. }
  4639. # $chart.Legend.Delete()
  4640. $excel.ScreenUpdating = $true
  4641. $excel.DisplayAlerts = $true
  4642.  
  4643. Get-ADRExcelComObjRelease -ComObjtoRelease $chart
  4644. Remove-Variable chart
  4645. Get-ADRExcelComObjRelease -ComObjtoRelease $ChartData
  4646. Remove-Variable ChartData
  4647. Get-ADRExcelComObjRelease -ComObjtoRelease $temp
  4648. Remove-Variable temp
  4649. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4650. Remove-Variable worksheet
  4651. }
  4652.  
  4653. Function Get-ADRExcelSort
  4654. {
  4655. <#
  4656. .SYNOPSIS
  4657. Sorts a WorkSheet in the active Workbook.
  4658.  
  4659. .DESCRIPTION
  4660. Sorts a WorkSheet in the active Workbook.
  4661.  
  4662. .PARAMETER ColumnName
  4663. [string]
  4664. Name of the Column.
  4665. #>
  4666. param (
  4667. [Parameter(Mandatory = $true)]
  4668. [string] $ColumnName
  4669. )
  4670.  
  4671. $worksheet = $workbook.Worksheets.Item(1)
  4672. $worksheet.Activate();
  4673.  
  4674. $ExcelColumn = ($worksheet.Columns.Find($ColumnName))
  4675. If ($ExcelColumn)
  4676. {
  4677. If ($ExcelColumn.Text -ne $ColumnName)
  4678. {
  4679. $BeginAddress = $ExcelColumn.Address(0,0,1,1)
  4680. $End = $False
  4681. Do {
  4682. Write-Verbose "[Get-ADRExcelSort] $($ExcelColumn.Text) selected instead of $($ColumnName) in the $($worksheet.Name) worksheet."
  4683. $ExcelColumn = ($worksheet.Columns.FindNext($ExcelColumn))
  4684. $Address = $ExcelColumn.Address(0,0,1,1)
  4685. If ( ($Address -eq $BeginAddress) -or ($ExcelColumn.Text -eq $ColumnName) )
  4686. {
  4687. $End = $True
  4688. }
  4689. } Until ($End -eq $True)
  4690. }
  4691. If ($ExcelColumn.Text -eq $ColumnName)
  4692. {
  4693. # Sort by Column
  4694. $workSheet.ListObjects.Item(1).Sort.SortFields.Clear()
  4695. $workSheet.ListObjects.Item(1).Sort.SortFields.Add($ExcelColumn) | Out-Null
  4696. $worksheet.ListObjects.Item(1).Sort.Apply()
  4697. }
  4698. Else
  4699. {
  4700. Write-Verbose "[Get-ADRExcelSort] $($ColumnName) not found in the $($worksheet.Name) worksheet."
  4701. }
  4702. }
  4703. Else
  4704. {
  4705. Write-Verbose "[Get-ADRExcelSort] $($ColumnName) not found in the $($worksheet.Name) worksheet."
  4706. }
  4707. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4708. Remove-Variable worksheet
  4709. }
  4710.  
  4711. Function Export-ADRExcel
  4712. {
  4713. <#
  4714. .SYNOPSIS
  4715. Automates the generation of the ADRecon report.
  4716.  
  4717. .DESCRIPTION
  4718. Automates the generation of the ADRecon report. If specific files exist, they are imported into the ADRecon report.
  4719.  
  4720. .PARAMETER ExcelPath
  4721. [string]
  4722. Path for ADRecon output folder containing the CSV files to generate the ADRecon-Report.xlsx
  4723.  
  4724. .OUTPUTS
  4725. Creates the ADRecon-Report.xlsx report in the folder.
  4726. #>
  4727. param(
  4728. [Parameter(Mandatory = $true)]
  4729. [string] $ExcelPath
  4730. )
  4731.  
  4732. $ExcelPath = $((Convert-Path $ExcelPath).TrimEnd("\"))
  4733. $ReportPath = -join($ExcelPath,'\','CSV-Files')
  4734. If (!(Test-Path $ReportPath))
  4735. {
  4736. Write-Warning "[Export-ADRExcel] Could not locate the CSV-Files directory ... Exiting"
  4737. Write-Verbose "[EXCEPTION] $($_.Exception.Message)"
  4738. Return $null
  4739. }
  4740. Get-ADRExcelComObj
  4741. If ($excel)
  4742. {
  4743. Write-Output "[*] Generating ADRecon-Report.xlsx"
  4744.  
  4745. $ADFileName = -join($ReportPath,'\','AboutADRecon.csv')
  4746. If (Test-Path $ADFileName)
  4747. {
  4748. Get-ADRExcelImport -ADFileName $ADFileName
  4749. Remove-Variable ADFileName
  4750.  
  4751. $workbook.Worksheets.Item(1).Name = "About ADRecon"
  4752. $workbook.Worksheets.Item(1).Hyperlinks.Add($workbook.Worksheets.Item(1).Cells.Item(3,2) , "https://github.com/sense-of-security/ADRecon", "" , "", "github.com/sense-of-security/ADRecon") | Out-Null
  4753. $workbook.Worksheets.Item(1).UsedRange.EntireColumn.AutoFit() | Out-Null
  4754. }
  4755.  
  4756. $ADFileName = -join($ReportPath,'\','Forest.csv')
  4757. If (Test-Path $ADFileName)
  4758. {
  4759. Get-ADRExcelWorkbook -Name "Forest"
  4760. Get-ADRExcelImport -ADFileName $ADFileName
  4761. Remove-Variable ADFileName
  4762. }
  4763.  
  4764. $ADFileName = -join($ReportPath,'\','Domain.csv')
  4765. If (Test-Path $ADFileName)
  4766. {
  4767. Get-ADRExcelWorkbook -Name "Domain"
  4768. Get-ADRExcelImport -ADFileName $ADFileName
  4769. $DomainObj = Import-CSV -Path $ADFileName
  4770. Remove-Variable ADFileName
  4771. $DomainName = -join($DomainObj[0].Value,"-")
  4772. Remove-Variable DomainObj
  4773. }
  4774.  
  4775. $ADFileName = -join($ReportPath,'\','Trusts.csv')
  4776. If (Test-Path $ADFileName)
  4777. {
  4778. Get-ADRExcelWorkbook -Name "Trusts"
  4779. Get-ADRExcelImport -ADFileName $ADFileName
  4780. Remove-Variable ADFileName
  4781. }
  4782.  
  4783. $ADFileName = -join($ReportPath,'\','Subnets.csv')
  4784. If (Test-Path $ADFileName)
  4785. {
  4786. Get-ADRExcelWorkbook -Name "Subnets"
  4787. Get-ADRExcelImport -ADFileName $ADFileName
  4788. Remove-Variable ADFileName
  4789. }
  4790.  
  4791. $ADFileName = -join($ReportPath,'\','Sites.csv')
  4792. If (Test-Path $ADFileName)
  4793. {
  4794. Get-ADRExcelWorkbook -Name "Sites"
  4795. Get-ADRExcelImport -ADFileName $ADFileName
  4796. Remove-Variable ADFileName
  4797. }
  4798.  
  4799. $ADFileName = -join($ReportPath,'\','FineGrainedPasswordPolicy.csv')
  4800. If (Test-Path $ADFileName)
  4801. {
  4802. Get-ADRExcelWorkbook -Name "Fine Grained Password Policy"
  4803. Get-ADRExcelImport -ADFileName $ADFileName
  4804. Remove-Variable ADFileName
  4805. }
  4806.  
  4807. $ADFileName = -join($ReportPath,'\','DefaultPasswordPolicy.csv')
  4808. If (Test-Path $ADFileName)
  4809. {
  4810. Get-ADRExcelWorkbook -Name "Default Password Policy"
  4811. Get-ADRExcelImport -ADFileName $ADFileName
  4812. Remove-Variable ADFileName
  4813.  
  4814. $excel.ScreenUpdating = $false
  4815. $worksheet = $workbook.Worksheets.Item(1)
  4816. # https://docs.microsoft.com/en-us/office/vba/api/excel.xlhalign
  4817. $worksheet.Range("B2:G10").HorizontalAlignment = -4108
  4818. # https://docs.microsoft.com/en-us/office/vba/api/excel.range.borderaround
  4819.  
  4820. "A2:B10", "C2:D10", "E2:F10", "G2:G10" | ForEach-Object {
  4821. $worksheet.Range($_).BorderAround(1) | Out-Null
  4822. }
  4823.  
  4824. # https://docs.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel.formatconditions.add?view=excel-pia
  4825. # $worksheet.Range().FormatConditions.Add
  4826. # http://dmcritchie.mvps.org/excel/colors.htm
  4827. # Values for Font.ColorIndex
  4828.  
  4829. $ObjValues = @(
  4830. # PCI Enforce password history (passwords)
  4831. "C2", '=IF(B2<4,TRUE, FALSE)'
  4832.  
  4833. # PCI Maximum password age (days)
  4834. "C3", '=IF(OR(B3=0,B3>90),TRUE, FALSE)'
  4835.  
  4836. # PCI Minimum password age (days)
  4837.  
  4838. # PCI Minimum password length (characters)
  4839. "C5", '=IF(B5<7,TRUE, FALSE)'
  4840.  
  4841. # PCI Password must meet complexity requirements
  4842. "C6", '=IF(B6<>TRUE,TRUE, FALSE)'
  4843.  
  4844. # PCI Store password using reversible encryption for all users in the domain
  4845.  
  4846. # PCI Account lockout duration (mins)
  4847. "C8", '=IF(AND(B8>=1,B8<30),TRUE, FALSE)'
  4848.  
  4849. # PCI Account lockout threshold (attempts)
  4850. "C9", '=IF(OR(B9=0,B9>6),TRUE, FALSE)'
  4851.  
  4852. # PCI Reset account lockout counter after (mins)
  4853.  
  4854. # ASD ISM Enforce password history (passwords)
  4855. "E2", '=IF(B2<8,TRUE, FALSE)'
  4856.  
  4857. # ASD ISM Maximum password age (days)
  4858. "E3", '=IF(OR(B3=0,B3>90),TRUE, FALSE)'
  4859.  
  4860. # ASD ISM Minimum password age (days)
  4861. "E4", '=IF(B4=0,TRUE, FALSE)'
  4862.  
  4863. # ASD ISM Minimum password length (characters)
  4864. "E5", '=IF(B5<13,TRUE, FALSE)'
  4865.  
  4866. # ASD ISM Password must meet complexity requirements
  4867. "E6", '=IF(B6<>TRUE,TRUE, FALSE)'
  4868.  
  4869. # ASD ISM Store password using reversible encryption for all users in the domain
  4870.  
  4871. # ASD ISM Account lockout duration (mins)
  4872.  
  4873. # ASD ISM Account lockout threshold (attempts)
  4874. "E9", '=IF(OR(B9=0,B9>5),TRUE, FALSE)'
  4875.  
  4876. # ASD ISM Reset account lockout counter after (mins)
  4877.  
  4878. # CIS Benchmark Enforce password history (passwords)
  4879. "G2", '=IF(B2<24,TRUE, FALSE)'
  4880.  
  4881. # CIS Benchmark Maximum password age (days)
  4882. "G3", '=IF(OR(B3=0,B3>60),TRUE, FALSE)'
  4883.  
  4884. # CIS Benchmark Minimum password age (days)
  4885. "G4", '=IF(B4=0,TRUE, FALSE)'
  4886.  
  4887. # CIS Benchmark Minimum password length (characters)
  4888. "G5", '=IF(B5<14,TRUE, FALSE)'
  4889.  
  4890. # CIS Benchmark Password must meet complexity requirements
  4891. "G6", '=IF(B6<>TRUE,TRUE, FALSE)'
  4892.  
  4893. # CIS Benchmark Store password using reversible encryption for all users in the domain
  4894. "G7", '=IF(B7<>FALSE,TRUE, FALSE)'
  4895.  
  4896. # CIS Benchmark Account lockout duration (mins)
  4897. "G8", '=IF(AND(B8>=1,B8<15),TRUE, FALSE)'
  4898.  
  4899. # CIS Benchmark Account lockout threshold (attempts)
  4900. "G9", '=IF(OR(B9=0,B9>10),TRUE, FALSE)'
  4901.  
  4902. # CIS Benchmark Reset account lockout counter after (mins)
  4903. "G10", '=IF(B10<15,TRUE, FALSE)' )
  4904.  
  4905. For ($i = 0; $i -lt $($ObjValues.Count); $i++)
  4906. {
  4907. $worksheet.Range($ObjValues[$i]).FormatConditions.Add([Microsoft.Office.Interop.Excel.XlFormatConditionType]::xlExpression, 0, $ObjValues[$i+1]) | Out-Null
  4908. $i++
  4909. }
  4910.  
  4911. "C2", "C3" , "C5", "C6", "C8", "C9", "E2", "E3" , "E4", "E5", "E6", "E9", "G2", "G3", "G4", "G5", "G6", "G7", "G8", "G9", "G10" | ForEach-Object {
  4912. $worksheet.Range($_).FormatConditions.Item(1).StopIfTrue = $false
  4913. $worksheet.Range($_).FormatConditions.Item(1).Font.ColorIndex = 3
  4914. }
  4915.  
  4916. $workbook.Worksheets.Item(1).Hyperlinks.Add($workbook.Worksheets.Item(1).Cells.Item(1,4) , "https://www.pcisecuritystandards.org/document_library?category=pcidss&document=pci_dss", "" , "", "PCI DSS v3.2.1") | Out-Null
  4917. $workbook.Worksheets.Item(1).Hyperlinks.Add($workbook.Worksheets.Item(1).Cells.Item(1,6) , "https://acsc.gov.au/infosec/ism/", "" , "", "2018 ISM Controls") | Out-Null
  4918. $workbook.Worksheets.Item(1).Hyperlinks.Add($workbook.Worksheets.Item(1).Cells.Item(1,7) , "https://www.cisecurity.org/benchmark/microsoft_windows_server/", "" , "", "CIS Benchmark 2016") | Out-Null
  4919.  
  4920. $excel.ScreenUpdating = $true
  4921. Get-ADRExcelComObjRelease -ComObjtoRelease $worksheet
  4922. Remove-Variable worksheet
  4923. }
  4924.  
  4925. $ADFileName = -join($ReportPath,'\','DomainControllers.csv')
  4926. If (Test-Path $ADFileName)
  4927. {
  4928. Get-ADRExcelWorkbook -Name "Domain Controllers"
  4929. Get-ADRExcelImport -ADFileName $ADFileName
  4930. Remove-Variable ADFileName
  4931. }
  4932.  
  4933. $ADFileName = -join($ReportPath,'\','DACLs.csv')
  4934. If (Test-Path $ADFileName)
  4935. {
  4936. Get-ADRExcelWorkbook -Name "DACLs"
  4937. Get-ADRExcelImport -ADFileName $ADFileName
  4938. Remove-Variable ADFileName
  4939. }
  4940.  
  4941. $ADFileName = -join($ReportPath,'\','SACLs.csv')
  4942. If (Test-Path $ADFileName)
  4943. {
  4944. Get-ADRExcelWorkbook -Name "SACLs"
  4945. Get-ADRExcelImport -ADFileName $ADFileName
  4946. Remove-Variable ADFileName
  4947. }
  4948.  
  4949. $ADFileName = -join($ReportPath,'\','GPOs.csv')
  4950. If (Test-Path $ADFileName)
  4951. {
  4952. Get-ADRExcelWorkbook -Name "GPOs"
  4953. Get-ADRExcelImport -ADFileName $ADFileName
  4954. Remove-Variable ADFileName
  4955. }
  4956.  
  4957. $ADFileName = -join($ReportPath,'\','gPLinks.csv')
  4958. If (Test-Path $ADFileName)
  4959. {
  4960. Get-ADRExcelWorkbook -Name "gPLinks"
  4961. Get-ADRExcelImport -ADFileName $ADFileName
  4962. Remove-Variable ADFileName
  4963. }
  4964.  
  4965. $ADFileName = -join($ReportPath,'\','DNSNodes','.csv')
  4966. If (Test-Path $ADFileName)
  4967. {
  4968. Get-ADRExcelWorkbook -Name "DNS Records"
  4969. Get-ADRExcelImport -ADFileName $ADFileName
  4970. Remove-Variable ADFileName
  4971. }
  4972.  
  4973. $ADFileName = -join($ReportPath,'\','DNSZones.csv')
  4974. If (Test-Path $ADFileName)
  4975. {
  4976. Get-ADRExcelWorkbook -Name "DNS Zones"
  4977. Get-ADRExcelImport -ADFileName $ADFileName
  4978. Remove-Variable ADFileName
  4979. }
  4980.  
  4981. $ADFileName = -join($ReportPath,'\','Printers.csv')
  4982. If (Test-Path $ADFileName)
  4983. {
  4984. Get-ADRExcelWorkbook -Name "Printers"
  4985. Get-ADRExcelImport -ADFileName $ADFileName
  4986. Remove-Variable ADFileName
  4987. }
  4988.  
  4989. $ADFileName = -join($ReportPath,'\','BitLockerRecoveryKeys.csv')
  4990. If (Test-Path $ADFileName)
  4991. {
  4992. Get-ADRExcelWorkbook -Name "BitLocker"
  4993. Get-ADRExcelImport -ADFileName $ADFileName
  4994. Remove-Variable ADFileName
  4995. }
  4996.  
  4997. $ADFileName = -join($ReportPath,'\','LAPS.csv')
  4998. If (Test-Path $ADFileName)
  4999. {
  5000. Get-ADRExcelWorkbook -Name "LAPS"
  5001. Get-ADRExcelImport -ADFileName $ADFileName
  5002. Remove-Variable ADFileName
  5003. }
  5004.  
  5005. $ADFileName = -join($ReportPath,'\','ComputerSPNs.csv')
  5006. If (Test-Path $ADFileName)
  5007. {
  5008. Get-ADRExcelWorkbook -Name "Computer SPNs"
  5009. Get-ADRExcelImport -ADFileName $ADFileName
  5010. Remove-Variable ADFileName
  5011.  
  5012. Get-ADRExcelSort -ColumnName "Name"
  5013. }
  5014.  
  5015. $ADFileName = -join($ReportPath,'\','Computers.csv')
  5016. If (Test-Path $ADFileName)
  5017. {
  5018. Get-ADRExcelWorkbook -Name "Computers"
  5019. Get-ADRExcelImport -ADFileName $ADFileName
  5020. Remove-Variable ADFileName
  5021.  
  5022. Get-ADRExcelSort -ColumnName "UserName"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement