├── AD-Expiry-Notification
├── AD-Account-Exp-Notify_Message-Body_NL.html
├── AD-Account-Exp-Notify_Message-Body_US.html
├── AD-Exp-Notify.cmd
├── AD-Exp-Notify.ps1
├── AD-Exp-Notify.xml
├── AD-Exp-Notify_Example-Logs-And-CSVs.zip
├── AD-Pwd-Exp-Notify_Message-Body_NL.html
├── AD-Pwd-Exp-Notify_Message-Body_US.html
├── README.md
├── iamTEC_AccountExpiration_NL.png
├── iamTEC_AccountExpiration_US.png
├── iamTEC_PasswordExpiration_NL.png
├── iamTEC_PasswordExpiration_US.png
├── scheduledTask_Notify Users With Expired Accounts And Or Passwords.xml
└── template_IAMTEC.png
├── AD-Schema-Extension-Conflict-Analyzer.ps1
├── Build-Password-Policy-Config-Report.ps1
├── Check-AD-Replication-Latency-Convergence.md
├── Check-AD-Replication-Latency-Convergence.ps1
├── Check-AD-Replication-Latency-Convergence.xml
├── Check-Connectivity-All-DCs-In-AD-Forest.md
├── Check-Connectivity-All-DCs-In-AD-Forest.ps1
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.md
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.xml
├── Images
├── Check-AD-Replication-Latency-Convergence_Picture01.png
├── Check-AD-Replication-Latency-Convergence_Picture02.png
├── Check-AD-Replication-Latency-Convergence_Picture03.png
├── Check-AD-Replication-Latency-Convergence_Picture04.png
├── Check-AD-Replication-Latency-Convergence_Picture05.png
├── Check-AD-Replication-Latency-Convergence_Picture06.png
├── Check-AD-Replication-Latency-Convergence_Picture07.png
├── Check-AD-Replication-Latency-Convergence_Picture08.png
├── Check-AD-Replication-Latency-Convergence_Picture09.png
├── Check-AD-Replication-Latency-Convergence_Picture10.png
├── Check-AD-Replication-Latency-Convergence_Picture11.png
├── Check-AD-Replication-Latency-Convergence_Picture12.png
├── Check-AD-Replication-Latency-Convergence_Picture13.png
├── Check-AD-Replication-Latency-Convergence_Picture14.png
├── Check-AD-Replication-Latency-Convergence_Picture15.png
├── Check-AD-Replication-Latency-Convergence_Picture16.png
├── Check-AD-Replication-Latency-Convergence_Picture17.png
├── Check-Connectivity-All-DCs-In-AD-Forest01.png
├── Check-Connectivity-All-DCs-In-AD-Forest02.png
├── Check-Connectivity-All-DCs-In-AD-Forest03.png
├── Check-Connectivity-All-DCs-In-AD-Forest04.png
├── Check-Connectivity-All-DCs-In-AD-Forest05.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture14.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture15.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture16.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture17.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture18.png
├── Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture19.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture01.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture02.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture03.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture04.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture05.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture06.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture07.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture08.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture09.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture10.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture11.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture12.png
├── OLD_Check-AD-Replication-Latency-Convergence_Picture13.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png
├── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png
└── OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png
├── LICENSE
├── Managing-ACEs-In-AD-Through-PowerShell.zip
├── README.md
├── Reset-KrbTgt-Password-For-RWDCs-And-RODCs.md
├── Reset-KrbTgt-Password-For-RWDCs-And-RODCs.ps1
├── Reset-KrbTgt-Password-For-RWDCs-And-RODCs.xml
├── Retrieve-List-Of-Conflicting-Objects.ps1
├── Scan-And-Check-All-Accounts-In-AD-Forest_01_Basic-Info.ps1
├── Scan-And-Check-All-Accounts-In-AD-Forest_02_Delegation-Info.ps1
├── Scan-And-Check-All-Accounts-In-AD-Forest_03_NC-Level-Permissions-Info.ps1
├── Scan-And-Check-All-Accounts-In-AD-Forest_04_Object-Level-Permissions-Info.ps1
└── Scan-And-Check-All-Accounts-In-AD-Forest_05_Account-And-Password-Hygiene-Info.ps1
/AD-Expiry-Notification/AD-Account-Exp-Notify_Message-Body_NL.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AD-Account-Expiration-Notification_NL
5 |
7 |
8 |
9 |
10 | !!! ATTENTIE | Actie Benodigd !!!
11 |
12 |
13 | Beste FIRST_NAME,
14 | Uw account 'PRINCIPAL_ACCOUNT_NAME' in het 'FQDN_DOMAIN' AD domein verloopt op ACCOUNT_EXPIRY_DATE . Wilt u a.u.b. z.s.m. een verzoek indienen om uw account 'PRINCIPAL_ACCOUNT_NAME' te verlengen?
15 | Om een verlenging aan te vragen voor uw account dient u de volgende stappen te gebruiken:
16 |
19 | U kunt NIET reageren op dit bericht!
20 | Bedankt!
21 | Uw Netwerk Beheerder
22 |
23 |
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Account-Exp-Notify_Message-Body_US.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AD-Account-Expiration-Notification_US
5 |
7 |
8 |
9 |
10 | !!! ATTENTION | Action Required !!!
11 |
12 |
13 | Dear FIRST_NAME,
14 | The account 'PRINCIPAL_ACCOUNT_NAME' in the 'FQDN_DOMAIN' AD domain will expire at ACCOUNT_EXPIRY_DATE . Please request an extension for your AD account 'PRINCIPAL_ACCOUNT_NAME' as soon as possible!
15 | To request an extension of your account use the following steps:
16 |
19 | Please DO NOT reply to e-mail message!
20 | Thanks!
21 | Your Network Administrator
22 |
23 |
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Exp-Notify.cmd:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | CLS
3 | COLOR 0E
4 | PowerShell.exe -ExecutionPolicy Bypass -file %0\..\AD-Exp-Notify.ps1
5 |
6 | ECHO.
7 | ECHO FINISHED!
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Exp-Notify.ps1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/AD-Exp-Notify.ps1
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Exp-Notify.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/AD-Exp-Notify.xml
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Exp-Notify_Example-Logs-And-CSVs.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/AD-Exp-Notify_Example-Logs-And-CSVs.zip
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Pwd-Exp-Notify_Message-Body_NL.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AD-Password-Expiration-Notification_NL
5 |
7 |
8 |
9 |
10 | !!! ATTENTIE | Actie Benodigd !!!
11 |
12 |
13 | Beste FIRST_NAME,
14 | Het huidige wachtwoord van het account 'PRINCIPAL_ACCOUNT_NAME' in het 'FQDN_DOMAIN' AD domein verloopt op PWD_EXPIRY_DATE . Wijzig a.u.b. uw wachtwoord zo snel als mogelijk!
15 | Het nieuwe wachtwoord moet aan de volgende eisen voldoen:
16 |
17 | Min. aantal karakters in een wachtwoord = 'PWD_MIN_LENGTH karakters' (Het minimum aantal karakters dat gebruikt moet worden in een wachtwoord)
18 | Min. wachtwoord gebruikersduur = 'PWD_MIN_AGE dagen' (Minimum aantal dagen dat een nieuw wachtwoord gebruikt moet worden voordat het weer gewijzigd mag worden)
19 | Max. wachtwoord gebruikersduur = 'PWD_MAX_AGE dagen' (Maximum aantal dagen dat een bestaande wachtwoord gebruikt mag worden nadat het weer gewijzigd moet worden)
20 | Aantal wachtwoorden die niet hergebruikt mogen worden = 'PWD_HISTORY' (Aantal nieuwe en unieke wachtwoorden die gebruikt moeten worden voordat een eerder gebruikt wachtwoord hergebruikt mag worden)
21 | Wachtwoord complexiteit aan? = PWD_COMPLEX' (Het nieuwe wachtwoord moet voldoen aan de complexiteits eisen wanneer geconfigureerd met 'TRUE')
22 |
23 | Wanneer wachtwoord complexiteit aan staat, zijn de wachtwoord eisen als volgt:
24 |
25 | Mag niet gelijk zijn aan de logon naam of delen ervan bevatten
26 | Moet minstens 6 karakters bevatten
27 | Moet karakters bevatten uit minstens 3 van de 4 onderstaande reeksen:
28 |
29 | Hoofdletters (A t/m Z)
30 | Kleine letters (a t/m z)
31 | Numerieke karakters (0 t/m 9)
32 | Speciale tekens (bijvoorbeeld, !, $, #, %)
33 |
34 |
35 |
36 | Om uw wachtwoord te wijzigen, opnieuw in te stellen of te registeren voor SSPR, gebruik een van de onderstaande methoden:
37 |
43 | Geef nooit uw persoonlijke wachtwoord aan derden!
44 | Wij zullen nooit om uw persoonlijke wachtwoord vragen!
45 | U kunt NIET reageren op dit bericht!
46 | Bedankt!
47 | Uw Netwerk Beheerder
48 |
49 |
--------------------------------------------------------------------------------
/AD-Expiry-Notification/AD-Pwd-Exp-Notify_Message-Body_US.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AD-Password-Expiration-Notification_US
5 |
7 |
8 |
9 |
10 | !!! ATTENTION | Action Required !!!
11 |
12 |
13 | Dear FIRST_NAME,
14 | The current password of the account 'PRINCIPAL_ACCOUNT_NAME' in the 'FQDN_DOMAIN' AD domain will expire at PWD_EXPIRY_DATE . Please change your password as soon as possible!
15 | The new password must meet the following requirements:
16 |
17 | Min. nr. of characters in a PWD = 'PWD_MIN_LENGTH characters' (The minimum number of characters to be used in a password)
18 | Min. PWD age = 'PWD_MIN_AGE days' (Minimum number of days the new password must be used before it can be changed again)
19 | Max. PWD age = 'PWD_MAX_AGE days' (Maximum number of days the new password can be used before it must be changed again)
20 | Nr. of previous PWDs in history = 'PWD_HISTORY' (Number of new and unique passwords required before an old password can be reused again)
21 | Password complexity enabled? = 'PWD_COMPLEX' (The new password must meet complexity requirements ONLY when configured to 'TRUE')
22 |
23 | If password complexity is enabled, the new password must meet the following requirements:
24 |
25 | Not contain the user's account name or parts of the user's full name that exceed 2 consecutive characters
26 | Be at least 6 characters in length
27 | Contain characters from 3 of the following 4 categories:
28 |
29 | Uppercase characters (A through Z)
30 | Lowercase characters (a through z)
31 | Numeric characters (0 through 9)
32 | Non-alphabetic characters (for example, !, $, #, %)
33 |
34 |
35 |
36 | To change/reset your password or register for SSPR use either one of the following steps:
37 |
43 | Never give out your personal password to anyone!
44 | We will never ask for your personal password!
45 | Please DO NOT reply to e-mail message!
46 | Thanks!
47 | Your Network Administrator
48 |
49 |
--------------------------------------------------------------------------------
/AD-Expiry-Notification/README.md:
--------------------------------------------------------------------------------
1 | # AD Expiration Notification
2 |
3 | ## Social Media Channels
4 | * [Visit my blog](https://jorgequestforknowledge.wordpress.com/)
5 | * [Follow me on twitter](https://twitter.com/JsQForKnowledge/)
6 | * [Follow me on facebook](https://www.facebook.com/JorgesQuestForKnowledge/)
7 | * [Follow me on linkedin](http://www.linkedin.com/in/jorgedealmeidapinto)
8 |
9 | ## Main Features
10 | * **Account Expiration Notification** - Send a notification to the corresponding user when the AD account is about to expire, as the number of days until the account expiration date falls within a defined warn period
11 | * **Password Expiration Notification** - Send a notification to the corresponding user when the password of the AD account is about to expire, as the number of days until the password expiration date falls within a defined warn period
12 |
13 | ## Getting Started
14 | * Determine the notification features to use globally
15 | * Determine the FROM e-mail address, the Test Mode TO e-mail address, the Support TO e-mail afddress and the mail/smtp server
16 | * Determine whatever is applicable the URLs for "Requesting Account Extension", "Changing Password", "Register for Self-Service Password Reset" and "Resetting Password"
17 | * Determine the AD Domains to target and for each AD domain determine if you want a specific DC or want to discover a DC, and within each AD domain which OUs need to be target
18 | * For each targeted OU determine which notification featiure you want to enable or disable and which language template to use
19 | * Determine how many HTML body template files and picture files are needed. Every HTML body template file targets a specific feature AND language. Do not have overlaps!
20 | * Determine the warning periods for every feature you enable
21 | * Determine the AD user account to use to execute the script
22 | * Configure the required AD permissions
23 | * Create the HTML body files and the picture files. See the included examples. The following variables can be used in the subject and/or HTML body files. It is not mandatory to use variables:
24 | * Generic:
25 | * IMAGE_BASE_FILE_NAME
26 | * FQDN_DOMAIN
27 | * NBT_DOMAIN
28 | * FIRST_NAME
29 | * LAST_NAME
30 | * DISPLAY_NAME
31 | * EMAIL_ADDRESS
32 | * UPN
33 | * SAM_ACCOUNT_NAME
34 | * PRINCIPAL_ACCOUNT_NAME
35 | * For accountExpiryNotification only:
36 | * ACCOUNT_EXPIRY_DATE
37 | * ACCOUNT_EXPIRE_IN_NUM_DAYS
38 | * ACCOUNT_EXTENSION_URL
39 | * For pwdExpiryNotification only
40 | * PWD_LAST_SET
41 | * PWD_EXPIRY_DATE
42 | * PWD_EXPIRE_IN_NUM_DAYS
43 | * PWD_MIN_LENGTH
44 | * PWD_MIN_AGE
45 | * PWD_MAX_AGE
46 | * PWD_HISTORY
47 | * PWD_COMPLEX
48 | * PWD_CHANGE_URL
49 | * SSPR_REGISTRATION_URL
50 | * PWD_RESET_URL
51 | * Configure the Windows Server to host and execute the script
52 | * Configure the XML configuration file of the script
53 | * After every is configured:
54 | (**REMARK**: When executing the script check screen output and or LOG files and any CSV files if enabled in the XML file. If users are in scope for notification, the screen output and/or the log file will publish non-zero values for at least one 'User Count Within Warning Period' and 'User Count To Be Notified'. At the same time, the CSV file will contain the list of users that would be notified)
55 | * Execute the PowerShell script manually (using the execution account through RUNAS) WITHOUT the '-force parameter', evaluate results and (re)configure whatever needs to be (re)configured
56 | * Execute the PowerShell script manually (using the execution account through RUNAS) WITH the '-force parameter' and execution mode 'DEV', evaluate results and (re)configure whatever needs to be (re)configured
57 | * Execute the PowerShell script manually (using the execution account through RUNAS) WITH the '-force parameter' and execution mode 'TEST', evaluate results and (re)configure whatever needs to be (re)configured
58 | * Execute the PowerShell script through the scheduled task WITHOUT the '-force parameter', evaluate results and (re)configure whatever needs to be (re)configured
59 | * Execute the PowerShell script through the scheduled task WITH the '-force parameter' and execution mode 'DEV', evaluate results and (re)configure whatever needs to be (re)configured
60 | * Execute the PowerShell script through the scheduled task WITH the '-force parameter' and execution mode 'TEST', evaluate results and (re)configure whatever needs to be (re)configured
61 | * Execute the PowerShell script through the scheduled task WITH the '-force parameter' and execution mode 'PROD', when you are ready to put this in production\
62 | (**REMARK**: Before running in PROD mode, make sure to notify users that they will start to receive e-mails about account/password expirations! Not doing this may end up in users seeing it as spam or phishing and that may overload the service desk!)
63 |
64 | ## Configuration - Script XML
65 | * The script uses the default 'AD-Exp-Notify.xml' file in the same folder as the PowerShell script. If the parameter '-xmlconfigfilepath' is used with the full path to the XML file, then that will be used instead.
66 | * Enable or disable at global level the notification features you need. By default all features are disabled:\
67 | (**REMARK**: Notifications will only work if enabled at global level!)
68 |
69 | ```XML
70 |
71 |
72 |
73 |
74 |
75 |
76 | ```
77 |
78 | * When NOT using the '-force' parameter, the script will always operate in TEST mode with NO mailings at all, no matter what the XML configuration file specifies. Try this first!
79 | * When using the '-force' parameter, the script will operate in the mode specified in the XM configuration file\
80 | (**REMARK**: When the execitionMode is 'DEV' then the mail address specified in 'toSMTPAddressInTestMode' will receive just 1 mail for every globally enabled feature!)\
81 | (**REMARK**: When the execitionMode is 'TEST' then the mail address specified in 'toSMTPAddressInTestMode' will receive all mails that would have been send to scoped individual users for every globally enabled feature and if a warn period is matched!)\
82 | (**REMARK**: When the execitionMode is 'PROD' then the scoped individual users will receive the mail for every globally enabled feature and if a warn period is matched!)\
83 |
84 | ```XML
85 |
86 | DEV
87 | ```
88 |
89 | * When sending an e-mail, the following e-mail address is the FROM/SENDER address:
90 |
91 | ```XML
92 |
93 | FROM_XXX@YYY.ZZZ
94 | ```
95 |
96 | * When sending an e-mail in DEV or TEST mode, the following e-mail address is the TO/RECIPIENT address:
97 |
98 | ```XML
99 |
100 | TO_XXX@YYY.ZZZ
101 | ```
102 |
103 | * When script encounters a pre-defined issue the following e-mail address is the TO/RECIPIENT address:
104 |
105 | ```XML
106 |
107 | TO_XXX@YYY.ZZZ
108 | ```
109 |
110 | * When script sends any e-mail the following specified mail/smtp server is used:
111 |
112 | ```XML
113 |
114 | XXX.YYY.ZZZ
115 | ```
116 |
117 | * When script sends a notification e-mail the following is the priority of that e-mail:
118 |
119 | ```XML
120 |
121 | XXX
122 | ```
123 |
124 | * When script sends a notification e-mail, depending on the notification type (account expiry notification or password expiry notification) and the language, the correct HTML body file and picture file are determined and used as the mail template:
125 |
126 | ```XML
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | ```
137 |
138 | * When users receives an e-mail that notifies about upcoming account expiry and in your guidance you want to provide a URL where users can request account extension, the following can be used:
139 |
140 | ```XML
141 |
142 |
143 | https://idmportal.iamtec.net:444/IdentityManagement/
144 | ```
145 |
146 | * When users receives an e-mail that notifies about upcoming password expiry and in your guidance you want to provide a URL where users can change their password, the following can be used:\
147 | (**REMARK**: If you want to use the ADFS Password Change Portal, the URL is 'https:///adfs/portal/updatepassword.aspx')\
148 | (**REMARK**: If you want to use the Azure AD Password Change Portal, the URL is 'https://account.activedirectory.windowsazure.com/ChangePassword.aspx')
149 | ```XML
150 |
151 |
152 |
153 | https://account.activedirectory.windowsazure.com/ChangePassword.aspx
154 | ```
155 |
156 | * When users receives an e-mail that notifies about upcoming password expiry and in your guidance you want to provide a URL where users can register for password reset, the following can be used:\
157 | (**REMARK**: If you want to use the FIM/MIM Registration Portal, the URL is 'https:///'. You must have this portal already in use, and the URL depends on what you configured during it installation)\
158 | (**REMARK**: If you want to use the combined Azure AD Password Security Info Registration Portal, the URL is 'https://aka.ms/setupsecurityinfo')
159 | ```XML
160 |
161 |
162 |
163 | https://aka.ms/setupsecurityinfo
164 | ```
165 |
166 | * When users receives an e-mail that notifies about upcoming password expiry and in your guidance you want to provide a URL where users can reset their password, the following can be used:\
167 | (**REMARK**: If you want to use the FIM/MIM Self-Service Password Reset Portal, the URL is 'https:///'. You must have this portal already in use, and the URL depends on what you configured during it installation)\
168 | (**REMARK**: If you want to use the Azure AD Password Reset Portal, the URL is 'https://passwordreset.microsoftonline.com/?whr=mydomain.com'. Do not forget to configure the domain at the end of the URL)
169 | ```XML
170 |
171 |
172 |
173 | https://passwordreset.microsoftonline.com/?whr=mydomain.com
174 | ```
175 |
176 | * When the script executes, a log file is created in the folder specified below. Specify the full path of the folder where log files should be created:
177 | ```XML
178 |
179 | C:\AD-Support\Scripts\AD-Expiry-Notification
180 | ```
181 |
182 |
183 | * When the script executes, with the following setting it cleans all log files, except the last specified number of log files:
184 | ```XML
185 |
186 | 30
187 | ```
188 |
189 | * When the script executes, with the following setting you can specify if CSV files should be created or not:
190 | ```XML
191 |
192 | ON
193 | ```
194 |
195 | * When the script executes, a csv file is created in the folder specified below if export of csv files has been enabled. Specify the full path of the folder where csv files should be created:
196 | ```XML
197 |
198 | C:\AD-Support\Scripts\AD-Expiry-Notification
199 | ```
200 |
201 | * When the script executes, with the following setting it cleans all csv files, except the last specified number of csv files:
202 | ```XML
203 |
204 | 30
205 | ```
206 |
207 | * When the script executes, with the following setting you can define a date and time format:
208 | ```XML
209 |
210 | yyyy-MM-dd HH:mm:ss
211 | ```
212 |
213 | * When the script executes, the following section determines which AD domains to target and in the AD domain which OUs with users to target. For each OU (Search Base) you can specify which feature to use, the language and the search scope to in the query. 'OneLevel' means only that specified OU, and 'Subtree' means the specified OU and any sub OUs if any:\
214 | (**REMARK**: For every AD domain, you can either list a specific DC through its FQDN to always target or you can specify DISCOVER so that a DC is discovered through the DC locator process. If you list a specific DC, then that DC must be available, otherwise the corresponding AD domain will not be processed)\
215 | (**REMARK**: Be aware NOT to overlap OUs as users might receive e-mails more than once! The only way to overlap an OU with sub OUs is if you specify the search scope 'OneLevel' for the top level OU and the search scope 'Subtree' for the sub OUs)\
216 | (**REMARK**: Only enable a feature for an OU/searchBase if it really is needed, otherwise do not enable it)\
217 | (**REMARK**: accountExpiryNotificationEnabled="true" : enables account expiration notifications for that OU/searchBase)\
218 | (**REMARK**: accountExpiryNotificationEnabled="false" : disables account expiration notifications for that OU/searchBase)\
219 | (**REMARK**: pwdExpiryNotificationEnabled="true" : enables password expiration notifications for that OU/searchBase)\
220 | (**REMARK**: pwdExpiryNotificationEnabled="false" : disables password expiration notifications for that OU/searchBase)\
221 | (**REMARK**: The language 'code' is used to match the correct HTML body file and picture file)
222 | ```XML
223 |
224 |
225 |
226 |
227 | OU=EMPLOYEES,OU=Org-Users,DC=IAMTEC,DC=NET
228 | OU=Users,OU=EMPLOYEES,OU=Org-Users,DC=IAMTEC,DC=NET
229 | OU=DoesNotExist1,OU=EMPLOYEES,OU=Org-Users,DC=IAMTEC,DC=NET
230 | OU=OU=CONTRACTORS,OU=Org-Users,DC=IAMTEC,DC=NET
231 | OU=Users,OU=OU=CONTRACTORS,OU=Org-Users,DC=IAMTEC,DC=NET
232 | OU=DoesNotExist2,OU=OU=CONTRACTORS,OU=Org-Users,DC=IAMTEC,DC=NET
233 | OU=Users,OU=CONTRACTORS,OU=Org-Users,DC=IAMTEC,DC=NET
234 | OU=Users,OU=CONTRACTORZZZ,OU=Org-Users,DC=IAMTEC,DC=NET
235 | OU=Users,OU=HISTORY1,OU=Org-Users,DC=IAMTEC,DC=NET
236 | OU=Users,OU=HISTORY2,OU=Org-Users,DC=IAMTEC,DC=NET
237 | OU=BLA,OU=Org-Users,DC=IAMTEC,DC=NET
238 |
239 |
240 | DC=TROOT,DC=NET
241 |
242 |
243 | DC=CHLD,DC=IAMTEC,DC=NET
244 |
245 |
246 | ```
247 |
248 | * When the script executes, and users in specified OUs/searchbases are checked, it will check, per enabled feature if the number days until expiry match a single warn period:\
249 | (**REMARK**: It is suggested to execute the script on a weekly basis and specify 1 or more warning periods taking a factor of 7 days into account)\
250 | (**REMARK**: Numbers shown are just examples used for testing and do not take the recommendation of the factor into account)\
251 | (**REMARK**: Be aware NOT to overlap warning periods)
252 | ```XML
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 | ```
277 |
278 | ## Configuration - Active Directory
279 | ### *Permissions*
280 | * NOT needed to be a member of Domain Admins, Enterprise Admins or any other powerfull AD group/role
281 | * A normal domain user is good enough
282 | * When using the script for notifications due to password expiry, the details of the Password Settings Objects (PSO) in the same AD domain as the targeted users must be read. By default only members of Domain Admins can read the contents of the PSO container. Instead of making the user account executing this script a member of Domain Admins, delegate Allow:Read permissions to that user account, preferrably through a security group if other security principals (e.g. admins, helpdesk, etc) require the same permissions for support and/or troubleshooting. For more information about this see the blog post: https://jorgequestforknowledge.wordpress.com/2007/08/09/windows-server-2008-fine-grained-password-policies/. For ANY AD Domain with users for which password expiry notifications are required, execute the following to delegate:
283 |
284 | ```BATCH
285 | DSACLS "\\\CN=Password Settings Container,CN=System," /G ":GR" /I:T
286 | ```
287 | * If the account executing the script does not own the mail address specified in the 'mailFromSender' in the XML configuration file, that execution account requires the 'Allow:Send As' permission on the AD account that does own that e-mail address. If the account that owns that e-mail address is also a member of any protected group, either directly or indirectly, you need to assign the 'Allow:Send As' permission on the AdminSDHolder object.\
288 | (**REMARK**: If the account executing the script does own the mail address, this additional configuration is not needed)\
289 | (**REMARK**: If you use an (open) internal relay server that authenticates based upon the IP address of the server the script is running on, this additional configuration is not needed)\
290 |
291 | ```BATCH
292 | For Account: DSACLS "\\\" /G ":CA;Send As"
293 | For AdminDSHolder: DSACLS "\\\CN=AdminSDHolder,CN=System," /G ":CA;Send As"
294 | ```
295 |
296 | ## Configuration - Windows Server
297 | * NOT needed to run on a domain controller
298 | * A regular Windows Server is good enough
299 | * 'Allow Log On As A Batch Job' user right is required when using a scheduled task
300 | * That can be configured as follows:
301 | * Grant-UserRight -Right SeBatchLogonRight -Account "\\\\ "\
302 | (**REMARK**: Part of PowerShell Module: https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0)\
303 | OR
304 | * NTRIGHTS.EXE +r SeBatchLogonRight -u "\\\\ "\
305 | (**REMARK**: Part of W2K3 Resource Kit Tools: https://www.microsoft.com/en-us/download/details.aspx?id=17657)\
306 | OR
307 | * Assign it through a GPO Policy (*Computer Configuration -> Policies --> Windows Settings --> Security Settings --> Local Policies --> User Rights Assignment --> Log on as a batch job*)
308 | * A scheduled task to execute the batch which in turn executes the powershell script\
309 | (**REMARK**: In all cases the default 'Least Privilege' is configured. Try that first to see if it works. However due to UAC when reading password related user properties you may need to reconfigure the scheduled task to use 'Highest Privileges')
310 | * That can be configured as follows:
311 | * Using the template "scheduledTask_Notify Users With Expired Accounts And Or Passwords.xml" to import. Before the import make sure to edit the template:
312 | * Replace 'DOMAIN\AUTHOR_USER ' with the corresponding info of the user used to import the scheduled task (*Section: Task\RegistrationInfo\Author*)
313 | * Replace 'DOMAIN\EXEC_USER ' with the corresponding info of the user used run the scheduled task on a regular basis (*Section: Task\Principals\Principal\UserId*)
314 | * Replace 'FULL PATH TO AD-Exp-Notify.cmd ' with the full path of the batch file 'AD-Exp-Notify.cmd' (*Section: Task\Actions\Exec\Command*)
315 | * Replace 'FULL PATH OF FOLDER OF AD-Exp-Notify.cmd ' with the full path of the folder containing the batch file 'AD-Exp-Notify.cmd' (*Section: Task\Actions\Exec\WorkingDirectory*)\
316 | OR
317 | * Assign it through a GPO Preference (*Computer Configuration -> Preferences --> Control Panel Settings --> Scheduled Tasks --> Local Policies --> User Rights Assignment*)\
318 | OR
319 | * Using PowerShell to create and configure the scheduled task
320 | ```PowerShell
321 | $scheduledTaskAction = New-ScheduledTaskAction -Execute "" -WorkingDirectory ""
322 | $scheduledTaskTrigger = New-ScheduledTaskTrigger -Weekly -WeeksInterval 1 -DaysOfWeek "" -At ""
323 | $scheduledTaskSettings = New-ScheduledTaskSettingsSet
324 | $scheduledTask = New-ScheduledTask -Action $scheduledTaskAction -Trigger $scheduledTaskTrigger -Settings $scheduledTaskSettings
325 | Register-ScheduledTask -TaskName "iamTEC_Notify Users With Expired Accounts And Or Passwords" -InputObject $scheduledTask -User "" -Password ''
326 | ```
327 |
328 | ## Examples
329 | #### If you execute the script without enabling any notification feature, you will see the following on screen
330 | 
331 | 
332 |
333 | #### If you execute the script without enabling any notification feature, you will see the following in the error e-mail
334 | 
335 |
336 | #### If you execute the script with notification features enabled, you will see something similar to the following on screen
337 | 
338 | 
339 | 
340 | 
341 | 
342 | 
343 | 
344 | 
345 | 
346 | 
347 | 
348 | 
349 | 
350 |
351 | #### If any AD domain and/or OU/searchBase specified does not exist, you will see something similar in the error e-mail
352 | 
353 | 
354 |
355 | #### If you execute the script with the '-force' parameter and DEV configured in the XML configuration file, you will see something similar to the following on screen (pay attention to only 1 e-mail being send per enabled notification feature)
356 | 
357 |
358 | #### If you execute the script with the '-force' parameter and DEV configured in the XML configuration file, you will see something similar to the following in the account expiration notification e-mail to the Test Mode User
359 | 
360 |
361 | #### If you execute the script with the '-force' parameter and DEV configured in the XML configuration file, you will see something similar to the following in the password expiration notification e-mail to the Test Mode User
362 | 
363 | 
364 |
365 | #### If you execute the script with the '-force' parameter and TEST configured in the XML configuration file, you will see something similar to the following on screen (pay attention to all e-mails being send to the Test Mode User for every scoped user)
366 | 
367 |
368 | #### If you execute the script with the '-force' parameter and TEST configured in the XML configuration file, you will see something similar to the following in the account expiration notification e-mail to the Test Mode User from one of the scoped users
369 | 
370 |
371 | #### If you execute the script with the '-force' parameter and TEST configured in the XML configuration file, you will see something similar to the following in the password expiration notification e-mail to the Test Mode User from one of the scoped users
372 | 
373 | 
374 |
375 | #### If you execute the script with the '-force' parameter and PROD configured in the XML configuration file, you will see something similar to the following on screen (pay attention to all e-mails being send to the individual users)
376 | 
--------------------------------------------------------------------------------
/AD-Expiry-Notification/iamTEC_AccountExpiration_NL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/iamTEC_AccountExpiration_NL.png
--------------------------------------------------------------------------------
/AD-Expiry-Notification/iamTEC_AccountExpiration_US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/iamTEC_AccountExpiration_US.png
--------------------------------------------------------------------------------
/AD-Expiry-Notification/iamTEC_PasswordExpiration_NL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/iamTEC_PasswordExpiration_NL.png
--------------------------------------------------------------------------------
/AD-Expiry-Notification/iamTEC_PasswordExpiration_US.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/iamTEC_PasswordExpiration_US.png
--------------------------------------------------------------------------------
/AD-Expiry-Notification/scheduledTask_Notify Users With Expired Accounts And Or Passwords.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/scheduledTask_Notify Users With Expired Accounts And Or Passwords.xml
--------------------------------------------------------------------------------
/AD-Expiry-Notification/template_IAMTEC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/AD-Expiry-Notification/template_IAMTEC.png
--------------------------------------------------------------------------------
/Check-AD-Replication-Latency-Convergence.md:
--------------------------------------------------------------------------------
1 | # SCRIPT: Check-AD-Replication-Latency-Convergence
2 |
3 | ## AUTHOR/FEEDBACK
4 |
5 | * Written By: Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]
6 | * Re-Written By: N.A.
7 | * Company: IAMTEC >> Identity | Security | Recovery [https://www.iamtec.eu/]
8 | * Blog: Jorge's Quest For Knowledge [http://jorgequestforknowledge.wordpress.com/]
9 | * For Feedback/Questions: scripts DOT gallery AT iamtec.eu
10 | * Please Describe Your Scenario As Best As Possible With As Much Detail As Possible.
11 | * If Applicable Describe What Does and/Or Does Not Work.
12 | * If Applicable Describe What Should Be/Work Different And Explain Why/How.
13 | * Please Add Screendumps.
14 |
15 | ## ORIGINAL SOURCE(S)
16 |
17 | *
18 |
19 | ## DISCLAIMER
20 |
21 | * The script is FREEWARE, you are free to distribute/update it, but always refer to the original source(s) as the location where you got it
22 | * This script is furnished "AS IS". NO warranty is expressed or implied!
23 | * I HAVE NOT tested it in every scenario or environment
24 | * ALWAYS TEST FIRST in lab environment to see if it meets your needs!
25 | * Use this script at YOUR OWN RISK! YOU ARE RESPONSIBLE FOR ANY OUTCOME/RESULT BY USING THIS SCRIPT!
26 | * I DO NOT warrant this script to be fit for any purpose, use or environment!
27 | * I have tried to check everything that needed to be checked, but I DO NOT guarantee the script does not have bugs!
28 | * I DO NOT guarantee the script will not damage or destroy your system(s), environment or anything else due to improper use or bugs!
29 | * I DO NOT accept liability in any way when making mistakes, use the script wrong or in any other way where damage is caused to your environment/systems!
30 | * If you do not accept these terms DO NOT use the script in any way and delete it immediately!
31 |
32 | ## KNOWN ISSUES/BUGS
33 |
34 | * The content of the HTML file in the browser might suddenly appear to be blank. This might resolve by itself during the refresh or when the admin refreshes manually
35 | * Reachability of a certain DC depends on the required port being open, AND the speed a DC responds back. If the configured timeout is too low while a high latency is experienced, increase the configured timeout by using the XML configuration file
36 |
37 | ## RELEASE NOTES
38 |
39 | * v1.0, 2024-12-11, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
40 |
41 | * Improved User Experience: Changed the layout of the output on screen to display a summary of the progress.
42 | * Improved User Experience: Added URL for documentation to the ORIGINAL SOURCE(S) section above
43 | * Improved User Experience: Support for an XML file to specify environment specific connection parameters. At the same time this also allows upgrades/updates of the script without loosing those specify environment specific connection parameters
44 | * Improved User Experience: For a more detailed view of the progress, that information will automatically be displayed through an HTML file in a browser and refreshed every 5 seconds to display any changes.
45 | * Code Improvement: Implemented StrictMode Latest Version (Tested On PoSH 5.x And 7.x)
46 | * Code Improvement: Replaced "Get-WmiObject" with "Get-CimInstance" to also support PowerShell 7.x
47 | * New Feature: Added the function "showProgress" to display the progress of an action
48 | * New Feature: Added parameter to skip opening the HTML in a browser to support automation
49 |
50 | * v0.9, 2024-09-03, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
51 |
52 | * Improved User Experience: Added at the beginning the output of the command line and all parameters used
53 | * Improved User Experience: Faster processing due to paralellel processing through RunSpaces. (MAJOR CHANGE and WILL IMPACT CPU/RAM usage when checking against many members!)
54 | To configure the behavior of the processing in the Runspaces, review and update as needed the variables "$runspacePoolMinThreads", "$runspacePoolMaxThreads" And "$delayInMilliSecondsBetweenChecks"
55 | Inspired by:
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | * Bug Fix: Added forgotten parameter to automatically cleanup orphaned canary objects when found
64 | * New Feature: Added parameter to skip cleaning of orphaned canary objects when found
65 | * New Feature: Added variable that specifies the delay in milliseconds between the checks for each DC/GC. The default is 0, which means NO DELAY and go for it!
66 | * New Feature: Added a parameter to allow the export of the results into a CSV
67 |
68 | * v0.8, 2024-07-30, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
69 |
70 | * Bug Fix: Fixed case sensitivity bug when specifying a Naming Context DN through the command line
71 |
72 | * v0.7, 2024-02-06, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
73 |
74 | * Improved User Experience: Added a check to determine if there are Temporary Canary Object leftovers from previous executions of the script that were not cleaned up because the script was aborted or it crashed
75 | * Improved User Experience: Previous the delta time was calculated when the object was found by the script and compare it to the start time. Now it provided 2 different timings:
76 | * The "TimeDiscvrd" (Time Discovered) specifies how much time it took to find/see the object on a DC
77 | * The "TimeReplctd" (Time Replicated) specifies how much time it took to reach the DC
78 | * Bug Fix: Fixed issue when the fsmoroleowner property did not contain a value
79 | * Improved User Experience: The naming context list presented is now consistently presented in the same order
80 |
81 | * v0.6, 2024-01-31, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
82 | * Code Improvement: Added additional information, minor changes
83 |
84 | * v0.5, 2024-01-28, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
85 |
86 | * Script Improvement: Complete rewrite of the script
87 | * New Feature: Parameters added to support automation
88 | * New Feature: Logging Function
89 | * New Feature: Support for all NCs (Configuration Partition As The Forest NC, Domain NCs With Domain Only Or Also Including GCs In Other AD Domains, And App NCs)
90 | * Code Improvement: As target RWDC use specific role owner, disccovered RWDC, specific RWDC
91 |
92 | * v0.4, 2014-02-11, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
93 | * Code Improvement: Added additional logic to determine if a DC is either an RWDC or RODC when it fails using the first logic and changed the layout a little bit
94 |
95 | * v0.3, 2014-02-09, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
96 | * Bug Fix: Solved a bug with regards to the detection/location of RWDCs and RODCs
97 |
98 | * v0.2, 2014-02-01, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
99 |
100 | * New Feature: Added STOP option
101 | * Added few extra columns to output extra info of DCs,
102 | * Code Improvement: Better detection of unavailable DCs/GCs
103 | * Added screen adjustment section
104 |
105 | * v0.1, 2013-03-02, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
106 | * Initial version of the script
107 |
108 | ## SYNOPSIS/DESCRIPTION
109 |
110 | This PoSH Script Checks The AD Replication Latency/Convergence Across Specified NC And Replication Scope
111 |
112 | This PoSH script provides the following functions:
113 |
114 | * It executes all checks in parallel at the same time against all DCs/GCs in scope.
115 | * It executes on a per specified NC basis. For multiple NCs use automation with parameters
116 | * For automation, it is possible to define the DN of an naming context, the replication scope (only applicable for domain NCs), and the RWDC to use as the source RWDC to create the temporary canary object on
117 | * It supports non-interacive mode through automation with parameters, or interactive mode
118 | * It supports AD replication convergence check for any NC within an AD forest.
119 | * Configuration Partition As The Forest NC to test AD replication convergence/latency across the AD forest. Connectivity check to DCs through TCP:LDAP/389 for the purpose of checking the existance of the canary object
120 | * Domain NCs with domain only scope to test AD replication convergence/latency across the AD domain. Connectivity check to DCs through TCP:LDAP/389
121 | * Domain NCs with domain and GCs scope to test AD replication convergence/latency across the AD domain and the GCs in other AD domains. Connectivity check to DCs through TCP:LDAP/389, and GCs through TCP:LDAP-GC/3268
122 | * App NCs to test AD replication convergence/latency across the application partition. Connectivity check to DCs through TCP:LDAP/389
123 | * As the source RWDC, it is possible to:
124 | * Use the FSMO
125 | * For the Configuration Partition => FSMO = RWDC with Domain Naming Master FSMO Role (Partitions (Container) Object, Attribute fSMORoleOwner has NTDS Settings Object DN of RWDC)
126 | * For the Domain Partition => FSMO = RWDC with PDC Emulator FSMO Role (Domain NC Object, Attribute fSMORoleOwner Has NTDS Settings Object DN of RWDC)
127 | * For the Application Partition => FSMO = RWDC with Infrastructure Master FSMO Role (Infrastructure Object, Attribute fSMORoleOwner has NTDS Settings Object DN of RWDC)
128 | * Use a discovered RWDC (best effort, especially with application partitions)
129 | * Specified the FQDN of a RWDC that hosts the naming context
130 | * For the temporary canary object:
131 | * Initially created on the source RWDC and deleted from the source RWDC at the end
132 | * ObjectClass = contact
133 | * Name = _adReplConvergenceCheckTempObject_yyyyMMddHHmmss (e.g. _adReplConvergenceCheckTempObject_20240102030405)
134 | * Description = ...!!!...TEMP OBJECT TO TEST AD REPLICATION LATENCY/CONVERGENCE THROUGH THE '<NC TYPE>'...!!!...
135 | * Container:
136 | * For the Configuration Partition => Container = "CN=Services,CN=Configuration,DC=<ROOT DOMAIN>,DC=<TLD>"
137 | * For the Domain Partition => Container = "CN=Users,DC=<DOMAIN>,DC=<TLD>"
138 | * For the Application Partition => Container = "<DN Of App Partition, e.g. DC=CustomAppNC OR DC=DomainDnsZones,DC=<DOMAIN>,DC=<TLD>"
139 | * Distinguished Name
140 | * For the Configuration Partition => DN = "CN=_adReplConvergenceCheckTempObject_yyyyMMddHHmmss,CN=Services,CN=Configuration,DC=<ROOT DOMAIN>,DC=<TLD>"
141 | * For the Domain Partition => DN = "CN=_adReplConvergenceCheckTempObject_yyyyMMddHHmmss,CN=Users,DC=<DOMAIN>,DC=<TLD>"
142 | * For the Application Partition => DN = "CN=_adReplConvergenceCheckTempObject_yyyyMMddHHmmss,<DN Of App Partition, e.g. DC=CustomAppNC OR DC=DomainDnsZones,DC=<DOMAIN>,DC=<TLD>"
143 | * In the PowerShell command prompt window the global progress is displayed. The same thing is also logged to a log file
144 | * When a default browser is available/configured, the generated HTML file will be opened and automatically refreshed every 5 seconds as the script progresses. This HTML file displays the DC specific state/result
145 | * It checks if specified NC exists. If not, the script aborts.
146 | * It checks if specified RWDC exists. If not, the script aborts.
147 | * At the end it checks if any Temporary Canary Objects exist from previous execution of the script and offers to clean up (In the chosen NC only!).
148 | * Disjoint namespaces and discontiguous namespaces are supported
149 | * The script DOES NOT allow or support the schema partition to be targeted!
150 | * The script uses default values for specific connection parameters. If those do not meet expectation, an XML configuration file can be used with custom values.
151 | * For the specific NC, the script also checks if any remaining canary objects exists from previous script executions that either failed or were aborted. It provides the option to also clean those or not. Through a parameter
152 | it allows to default to always clean previous canary objects when found. This behavior is ignored when the parameter to skip the check of previous canary objects is used
153 | * In addition to displaying the end results on screen, it is also possible to export those end results to a CSV file
154 | * Through a parameter it is possible to not open the generated HTML in the default browser
155 | * Through a parameter it is possible to skip the check of previous canary objects
156 | * The script supports automation by using parameters with pre-specified details of the targeted Naming Context, if applicable the targeted Replication Scope and the targeted source RWDC
157 |
158 | ## PARAMETER(S)
159 |
160 | cleanupOrhanedCanaryObjects
161 |
162 | * With this parameter it is possible to automatically cleanup orphaned canary objects when found
163 |
164 | exportResultsToCSV
165 |
166 | * With this parameter it is possible to export the results to a CSV file in addition of displaying it on screen on in the log file
167 |
168 | skipOpenHTMLFileInBrowser
169 |
170 | * With this parameter it is possible to not open the HTML file in the default browser
171 |
172 | skipCheckForOrphanedCanaryObjects
173 |
174 | * With this parameter it is possible to not check for orphaned canary objects
175 |
176 | targetedReplScope
177 |
178 | * With this parameter it is possible to specify the replication scope when targeting a domain NC, being "Domain Only" (DomainOnly) or "Domain And GCs" (DomainAndGCs)
179 |
180 | targetNCDN
181 |
182 | * With this parameter it is possible to specify the DN of a naming Context to target for AD Replication Convergence/Latency check
183 |
184 | targetRWDC
185 |
186 | * With this parameter it is possible to specify the RWDC to use to create the temporary canary object on. Options that are available for this are "Fsmo", "Discover" or the FQDN of an RWDC
187 |
188 | ## EXAMPLE(S)
189 |
190 | Check The AD Replication Convergence/Latency Using Interactive Mode
191 |
192 | ``` powershell
193 | .\Check-AD-Replication-Latency-Convergence.ps1
194 | ```
195 |
196 | Check The AD Replication Convergence/Latency Using Automated Mode For The NC "DC=CustomAppNC1" Using The Fsmo Role Owner As The Source RWDC To Create The Temporary Canary Object On
197 |
198 | ``` powershell
199 | .\Check-AD-Replication-Latency-Convergence.ps1 -targetNCDN "DC=CustomAppNC1" -targetRWDC Fsmo
200 | ```
201 |
202 | Check The AD Replication Convergence/Latency Using Automated Mode For The NC "CN=Configuration,DC=IAMTEC,DC=NET" Using The Fsmo Role Owner As The Source RWDC To Create The Temporary Canary Object On
203 |
204 | ``` powershell
205 | .\Check-AD-Replication-Latency-Convergence.ps1 -targetNCDN "CN=Configuration,DC=IAMTEC,DC=NET" -targetRWDC Discover
206 | ```
207 |
208 | Check The AD Replication Convergence/Latency Using Automated Mode For The NC "DC=IAMTEC,DC=NET" Using A Specific RWDC As The Source RWDC To Create The Temporary Canary Object On, And Only Check Within The Domain Itself
209 |
210 | ``` powershell
211 | .\Check-AD-Replication-Latency-Convergence.ps1 -targetNCDN "DC=IAMTEC,DC=NET" -targetedReplScope DomainOnly -targetRWDC "R1FSRWDC1.IAMTEC.NET"
212 | ```
213 |
214 | Check The AD Replication Convergence/Latency Using Automated Mode For The NC "DC=IAMTEC,DC=NET" Using A Specific RWDC As The Source RWDC To Create The Temporary Canary Object On, And Check Within The Domain And GCs
215 |
216 | ``` powershell
217 | .\Check-AD-Replication-Latency-Convergence.ps1 -targetNCDN "DC=IAMTEC,DC=NET" -targetedReplScope DomainAndGCs -targetRWDC "R1FSRWDC1.IAMTEC.NET"
218 | ```
219 |
220 | ## NOTES
221 |
222 | * To execute this script, the account running the script MUST have the permissions to create and delete the object type in the container used of the specified naming context. Being a member of the Enterprise Admins group
223 | in general allows the usage of the script against any naming context
224 | * The credentials used are the credentials of the logged on account. It is not possible to provided other credentials. Other credentials could maybe be used through RUNAS /NETONLY /USER
225 | * No check is done for the required permissions. The script simply assumes the required permissions are available. If not, errors will occur
226 | * The script DOES NOT allow or support the schema partition to be targeted!
227 | * No PowerShell modules are needed to use this script
228 | * Script Has StrictMode Enabled For Latest Version - Tested With PowerShell 7.4.6
229 | * Reachbility is determined by checking against the required ports (TCP:LDAP/389 for DCs, and where applicable TCP:LDAP-GC/3268) and if the DC/GC responds fast enough before the defined connection timeout
230 | * The XML file for the environment specific oonnection parameters should have the exact same name as the script and must be in the same folder as the script. If the script is renamed, the XML should be renamed accordingly.
231 | For example, if the script is called "Check-AD-Replication-Latency-Convergence_v10.ps1", the XML file should be called "Check-AD-Replication-Latency-Convergence_v10.xml". When a decision is made to use the XML
232 | Configuration File, then ALL connection parameters MUST be defined in it. It is an all or nothing thing. The structure of the XML file is:
233 |
234 | ```XML
235 |
236 |
237 |
238 |
239 | TRUE_OR_FALSE
240 |
241 |
242 | REPLACE_WITH_NUMERIC_VALUE
243 |
244 |
245 | REPLACE_WITH_NUMERIC_VALUE
246 |
247 |
248 | REPLACE_WITH_NUMERIC_VALUE
249 |
250 |
251 | REPLACE_WITH_NUMERIC_VALUE
252 |
253 |
254 | REPLACE_WITH_NUMERIC_VALUE
255 |
256 |
257 | ```
258 |
259 | ## SCREENSHOTS (NEW WAY OF EXECUTION AND PROCESSING!)
260 |
261 | 
262 |
263 | 
264 |
265 | 
266 |
267 | 
268 |
269 | 
270 |
271 | 
272 |
273 | 
274 |
275 | 
276 |
277 | 
278 |
279 | 
280 |
281 | 
282 |
283 | 
284 |
285 | 
286 |
287 | 
288 |
289 | 
290 |
291 | 
292 |
293 | 
294 |
295 | ## SCREENSHOTS (PREVIOUS WAY OF EXECUTION AND PROCESSING!)
296 |
297 | 
298 |
299 | 
300 |
301 | 
302 |
303 | 
304 |
305 | 
306 |
307 | 
308 |
309 | 
310 |
311 | 
312 |
313 | 
314 |
315 | 
316 |
317 | 
318 |
319 | 
320 |
321 | 
322 |
--------------------------------------------------------------------------------
/Check-AD-Replication-Latency-Convergence.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FALSE
5 |
6 |
7 | 500
8 |
9 |
10 | 30
11 |
12 |
13 | 1
14 |
15 |
16 | 1024
17 |
18 |
19 | 500
20 |
--------------------------------------------------------------------------------
/Check-Connectivity-All-DCs-In-AD-Forest.md:
--------------------------------------------------------------------------------
1 | # SCRIPT: Check-Connectivity-All-DCs-In-AD-Forest
2 |
3 | ## AUTHOR/FEEDBACK
4 |
5 | * Written By: Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]
6 | * Re-Written By: N.A.
7 | * Company: IAMTEC >> Identity | Security | Recovery [https://www.iamtec.eu/]
8 | * Blog: Jorge's Quest For Knowledge [http://jorgequestforknowledge.wordpress.com/]
9 | * For Feedback/Questions: scripts DOT gallery AT iamtec.eu
10 | * Please Describe Your Scenario As Best As Possible With As Much Detail As Possible.
11 | * If Applicable Describe What Does and/Or Does Not Work.
12 | * If Applicable Describe What Should Be/Work Different And Explain Why/How.
13 | * Please Add Screendumps.
14 |
15 | ## ORIGINAL SOURCE(S)
16 |
17 | * Script:
18 |
19 | ## DISCLAIMER
20 |
21 | * The script is FREEWARE, you are free to distribute/update it, but always refer to the original source(s) as the location where you got it
22 | * This script is furnished "AS IS". NO warranty is expressed or implied!
23 | * I HAVE NOT tested it in every scenario or environment
24 | * ALWAYS TEST FIRST in lab environment to see if it meets your needs!
25 | * Use this script at YOUR OWN RISK! YOU ARE RESPONSIBLE FOR ANY OUTCOME/RESULT BY USING THIS SCRIPT!
26 | * I DO NOT warrant this script to be fit for any purpose, use or environment!
27 | * I have tried to check everything that needed to be checked, but I DO NOT guarantee the script does not have bugs!
28 | * I DO NOT guarantee the script will not damage or destroy your system(s), environment or anything else due to improper use or bugs!
29 | * I DO NOT accept liability in any way when making mistakes, use the script wrong or in any other way where damage is caused to your environment/systems!
30 | * If you do not accept these terms DO NOT use the script in any way and delete it immediately!
31 |
32 | ## KNOWN ISSUES/BUGS
33 |
34 | * N.A.
35 |
36 | ## RELEASE NOTES
37 |
38 | * v0.1, 2025-02-20, Jorge de Almeida Pinto [MVP Identity And Access - Security / Lead Identity/Security Architect]:
39 | * Initial version of the script
40 |
41 | ## SYNOPSIS/DESCRIPTION
42 |
43 | This PoSH Script Test Connectivity To Targeted DCs For Specified (TCP) Ports
44 |
45 | This PoSH script provides the following functions:
46 |
47 | * Create a list of DCs to target
48 | * Check connectivity for specified TCP ports for targeted DCs
49 |
50 | ## PARAMETER(S)
51 |
52 | N.A.
53 |
54 | ## EXAMPLE(S)
55 |
56 | Execute The Script - On-Demand
57 |
58 | ``` powershell
59 | .\Check-Connectivity-All-DCs-In-AD-Forest.ps1
60 | ```
61 |
62 | ## NOTES
63 |
64 | * N.A.
65 |
66 | ## SCREENSHOTS
67 |
68 | 
69 |
70 | 
71 |
72 | 
73 |
74 | 
75 |
76 | 
77 |
--------------------------------------------------------------------------------
/Check-Connectivity-All-DCs-In-AD-Forest.ps1:
--------------------------------------------------------------------------------
1 | ###
2 | # Parameters Used By Script
3 | ###
4 | # N.A.
5 |
6 | ###
7 | # Version Of Script
8 | ###
9 | $version = "v0.1, 2025-02-20"
10 |
11 | <#
12 | AUTHOR
13 | Written By....................: Jorge de Almeida Pinto [Jorge de Almeida Pinto [MVP Identity And Access - Security / Lead Identity/Security Architect]:]
14 | Re-Written By.................: N.A.
15 | Company.......................: IAMTEC >> Identity | Security | Recovery [https://www.iamtec.eu/]
16 | Blog..........................: Jorge's Quest For Knowledge [http://jorgequestforknowledge.wordpress.com/]
17 | For Feedback/Questions........: scripts.gallery@iamtec.eu
18 | --> Please Describe Your Scenario As Best As Possible With As Much Detail As Possible.
19 | --> If Applicable Describe What Does and/Or Does Not Work.
20 | --> If Applicable Describe What Should Be/Work Different And Explain Why/How.
21 | --> Please Add Screendumps.
22 |
23 | ORIGINAL SOURCES
24 | - https://github.com/zjorz/Public-AD-Scripts/blob/master/Check-Connectivity-All-DCs-In-AD-Forest.md
25 | - https://github.com/zjorz/Public-AD-Scripts/blob/master/Check-Connectivity-All-DCs-In-AD-Forest.ps1
26 |
27 | DISCLAIMER
28 | - The script is FREEWARE, you are free to distribute/update it, but always refer to the original source(s) as the location where you got it
29 | - This script is furnished "AS IS". NO warranty is expressed or implied!
30 | - I HAVE NOT tested it in every scenario or environment
31 | - ALWAYS TEST FIRST in lab environment to see if it meets your needs!
32 | - Use this script at YOUR OWN RISK! YOU ARE RESPONSIBLE FOR ANY OUTCOME/RESULT BY USING THIS SCRIPT!
33 | - I DO NOT warrant this script to be fit for any purpose, use or environment!
34 | - I have tried to check everything that needed to be checked, but I DO NOT guarantee the script does not have bugs!
35 | - I DO NOT guarantee the script will not damage or destroy your system(s), environment or anything else due to improper use or bugs!
36 | - I DO NOT accept liability in any way when making mistakes, use the script wrong or in any other way where damage is caused to your environment/systems!
37 | - If you do not accept these terms DO NOT use the script in any way and delete it immediately!
38 |
39 | TODO
40 | - Target AD Forest by FQDN
41 | - Target AD Domain by FQDN
42 | - Target Specific DCs by FQDN
43 | - Check only GC ports when DC is GC
44 | - Check only DNS port when DC is DNS server
45 |
46 | KNOWN ISSUES/BUGS
47 | - N.A.
48 |
49 | RELEASE NOTES
50 | v0.1, 2025-02-20, Jorge de Almeida Pinto [MVP Identity And Access - Security / Lead Identity/Security Architect]:
51 | - Initial version of the script
52 | #>
53 |
54 | <#
55 | .SYNOPSIS
56 | This PoSH Script Test Connectivity To Targeted DCs For Specified (TCP) Ports
57 |
58 | .DESCRIPTION
59 | This PoSH script provides the following functions:
60 | - Create a list of DCs to target
61 | - Check connectivity for specified TCP ports for targeted DCs
62 |
63 | .EXAMPLE
64 | Execute The Script - On-Demand
65 |
66 | .\Check-Connectivity-All-DCs-In-AD-Forest.ps1
67 |
68 | .NOTES
69 | - N.A.
70 | #>
71 |
72 | ###
73 | # Functions Used In Script
74 | ###
75 |
76 | ### FUNCTION: Logging Data To The Log File
77 | Function writeLog {
78 | Param(
79 | [string]$dataToLog,
80 | [string]$lineType,
81 | [bool]$logFileOnly,
82 | [bool]$noDateTimeInLogLine,
83 | [bool]$ignoreRemote
84 | )
85 |
86 | $dateTime = Get-Date
87 | $datetimeLocal = $(Get-Date $dateTime -format "yyyy-MM-dd HH:mm:ss") # Local Time
88 | $datetimeUniversal = $(Get-Date $dateTime.ToUniversalTime() -format "yyyy-MM-dd HH:mm:ss") # Universal Time
89 | $datetimeLogLine = "[UT:" + $datetimeUniversal + " | LT:" + $datetimeLocal + "] : "
90 | If ($ignoreRemote -ne $true) {
91 | If ($noDateTimeInLogLine -eq $true) {
92 | Out-File -filepath "$logFilePath" -append -inputObject "$dataToLog"
93 | }
94 | If ($noDateTimeInLogLine -eq $false) {
95 | Out-File -filepath "$logFilePath" -append -inputObject "$datetimeLogLine$dataToLog"
96 | }
97 | }
98 | If ($logFileOnly -eq $false) {
99 | If ($([string]::IsNullOrEmpty($lineType))) {
100 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Yellow
101 | }
102 | If ($lineType -eq "SUCCESS") {
103 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Green
104 | }
105 | If ($lineType -eq "ERROR") {
106 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
107 | }
108 | If ($lineType -eq "WARNING") {
109 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
110 | }
111 | If ($lineType -eq "MAINHEADER") {
112 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Magenta
113 | }
114 | If ($lineType -eq "HEADER") {
115 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor DarkCyan
116 | }
117 | If ($lineType -eq "REMARK") {
118 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Cyan
119 | }
120 | If ($lineType -eq "DEFAULT") {
121 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Yellow
122 | }
123 | If ($lineType -eq "REMARK-IMPORTANT") {
124 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Green
125 | }
126 | If ($lineType -eq "REMARK-MORE-IMPORTANT") {
127 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Yellow
128 | }
129 | If ($lineType -eq "REMARK-MOST-IMPORTANT") {
130 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
131 | }
132 | If ($lineType -eq "ACTION") {
133 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor White
134 | }
135 | If ($lineType -eq "ACTION-NO-NEW-LINE") {
136 | Write-Host "$datetimeLogLine$dataToLog" -NoNewline -ForeGroundColor White
137 | }
138 | }
139 | }
140 |
141 | ### FUNCTION: Test Resolving The Server Name And Connectivity Over The Specified TCP Port
142 | Function portConnectionCheck {
143 | <#
144 | .SYNOPSIS
145 | This Code Checks If A Specific TCP Port Is Open/Reachable For The Defined Server
146 |
147 | .DESCRIPTION
148 | This Code Checks If A Specific TCP Port Is Open/Reachable For The Defined Server
149 |
150 | .PARAMETER serverIPOrFQDN
151 | The IP Address Or FQDN Of The Server To Check Against.
152 |
153 | .PARAMETER port
154 | The Numeric Value For A Specific Port That Needs To Be Checked
155 |
156 | .PARAMETER timeOut
157 | The Number Of Milliseconds For The Time Out
158 | #>
159 |
160 | [cmdletbinding()]
161 | Param(
162 | [Parameter(Mandatory = $TRUE)]
163 | [string]$serverIPOrFQDN,
164 |
165 | [Parameter(Mandatory = $TRUE)]
166 | [int]$port,
167 |
168 | [Parameter(Mandatory = $FALSE)]
169 | [int]$timeOut
170 | )
171 |
172 | Begin {
173 | If ([int]$timeOut -eq 0) {
174 | [int]$timeOut = 1000
175 | }
176 | }
177 |
178 | Process {
179 | # Validate If An IP Address Has Been Provided, And If NOT Try To Resolve The FQDN
180 | $regexIPv4 = "^(?:(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)$"
181 | If ($serverIPOrFQDN -notmatch $regexIPv4) {
182 | # Test To See If The HostName Is Resolvable At All
183 | Try {
184 | [Void]$([System.Net.Dns]::GetHostEntry($serverIPOrFQDN))
185 | } Catch {
186 | Return "ERROR"
187 | }
188 | }
189 |
190 | # Test If The Server Is Reachable Over The Specified TCP Port
191 | $tcpPortSocket = $null
192 | $tcpPortSocket = New-Object System.Net.Sockets.TcpClient
193 |
194 | $portConnect = $null
195 | $portConnect = $tcpPortSocket.BeginConnect($serverIPOrFQDN, $port, $null, $null)
196 |
197 | $tcpPortWait = $null
198 | $tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut, $false)
199 |
200 | If (!$tcpPortWait) {
201 | $tcpPortSocket.Close()
202 |
203 | Return "ERROR"
204 | } Else {
205 | $ErrorActionPreference = "SilentlyContinue"
206 |
207 | [Void]$($tcpPortSocket.EndConnect($portConnect))
208 | If (!$?) {
209 | Return "ERROR"
210 | } Else {
211 | Return "SUCCESS"
212 | }
213 |
214 | $tcpPortSocket.Close()
215 |
216 | $ErrorActionPreference = "Continue"
217 | }
218 | }
219 | }
220 |
221 | ###
222 | # Clear The Screen
223 | ###
224 | Clear-Host
225 |
226 | ###
227 | # Configure The Appropriate Screen And Buffer Size To Make Sure Everything Fits Nicely
228 | ###
229 | $randomNr = Get-Random -Minimum 1000 -Maximum 9999
230 | $windowTitle = "+++ CHECK CONNECTIVITY TARGETED DCS +++ ($randomNr)"
231 | $uiConfig = (Get-Host).UI.RawUI
232 | $host.UI.RawUI.WindowTitle = $windowTitle
233 | Start-Sleep -s 1
234 | $poshProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $windowTitle }
235 | $poshProcessName = $poshProcess.ProcessName
236 | $poshProcessId = $poshProcess.Id
237 | If ($poshProcessName -eq "WindowsTerminal") {
238 | Get-Process -Id $poshProcessId | Set-Window -X 100 -Y 100 -Width 1800 -Height 800 # -Passthru
239 | } ElseIf ($poshProcessName -like "*powershell_ise*") {
240 | Write-Host ""
241 | Write-Host "The Script Is Being Executed From A PowerShell_ISE Command Prompt Window, Which IS NOT Supported!..." -ForeGroundColor Red
242 | Write-Host "Please Rerun The Script From A PowerShell Command Prompt Window!..." -ForeGroundColor Red
243 | Write-Host ""
244 | Write-Host "Aborting Script..." -ForeGroundColor Red
245 | Write-Host ""
246 |
247 | BREAK
248 | } Else {
249 | $uiConfig.ForegroundColor = "Yellow"
250 | $uiConfigBufferSize = $uiConfig.BufferSize
251 | $uiConfigBufferSize.Width = 400
252 | $uiConfigBufferSize.Height = 9999
253 | $uiConfigScreenSizeMax = $uiConfig.MaxPhysicalWindowSize
254 | $uiConfigScreenSizeMaxWidth = $uiConfigScreenSizeMax.Width
255 | $uiConfigScreenSizeMaxHeight = $uiConfigScreenSizeMax.Height
256 | $uiConfigScreenSize = $uiConfig.WindowSize
257 | If ($uiConfigScreenSizeMaxWidth -lt 200) {
258 | $uiConfigScreenSize.Width = $uiConfigScreenSizeMaxWidth
259 | } Else {
260 | $uiConfigScreenSize.Width = 200
261 | }
262 | If ($uiConfigScreenSizeMaxHeight -lt 75) {
263 | $uiConfigScreenSize.Height = $uiConfigScreenSizeMaxHeight - 5
264 | } Else {
265 | $uiConfigScreenSize.Height = 75
266 | }
267 | $uiConfig.BufferSize = $uiConfigBufferSize
268 | $uiConfig.WindowSize = $uiConfigScreenSize
269 | }
270 |
271 | ###
272 | # Definition Of Some Constants
273 | ###
274 | $scriptFullPath = $MyInvocation.MyCommand.Definition
275 | $currentScriptFolderPath = $null
276 | If ($scriptFullPath -match "^.*\:\\") {
277 | $currentScriptFolderPath = Split-Path $scriptFullPath
278 | } Else {
279 | $currentScriptFolderPath = (Get-Location).Path
280 | }
281 | $timeOut = 500
282 | $execDateTime = Get-Date
283 | $execDateTimeForLog = Get-Date $execDateTime -Format "yyyy-MM-dd HH:mm:ss"
284 | $execDateTimeForFileName = Get-Date $execDateTime -Format "yyyy-MM-dd_HH.mm.ss"
285 | $thisADForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
286 | $adForestFQDN = $thisADForest.Name
287 | $adForestNCDN = "DC=" + $adForestFQDN.Replace(".",",DC=")
288 | $adForestRWDCFQDN = $thisADForest.NamingRoleOwner.Name
289 | $logFilePath = Join-Path $currentScriptFolderPath $($execDateTimeForFileName + "_" + $adForestFQDN + "_" + "Check-Connectivity-All-DCs-In-AD-Forest.log")
290 | $localComputerName = (Get-CimInstance -class Win32_ComputerSystem).Name
291 | $localComputerDomain = (Get-CimInstance -class Win32_ComputerSystem).Domain
292 | $localComputerFQDN = $localComputerName + "." + $localComputerDomain
293 | # SOURCE: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/service-overview-and-network-port-requirements
294 | # SOURCE: https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/config-firewall-for-ad-domains-and-trusts
295 | # SOURCE: https://lazyadmin.nl/it/domain-controller-ports/
296 | $portsToCheck = @()
297 | $portsToCheck += 53 # TCP:DNS - Reliable Result ONLY When DNS Is Installed Is On The DC (AD Integrated DNS)
298 | $portsToCheck += 88 # TCP:Kerberos
299 | $portsToCheck += 135 # TCP:RPC Endpoint Mapper
300 | $portsToCheck += 389 # TCP:LDAP
301 | $portsToCheck += 445 # TCP:SMB
302 | $portsToCheck += 464 # TCP:Kerberos Password Change
303 | $portsToCheck += 636 # TCP:LDAP (Over SSL)
304 | $portsToCheck += 3268 # TCP:GC - Reliable Result ONLY When DC Is A GC
305 | $portsToCheck += 3269 # TCP:GC (Over SSL) - Reliable Result ONLY When DC Is A GC
306 | $portsToCheck += 5985 # TCP:WinRM/RemotePowerShell
307 | $portsToCheck += 5986 # TCP:WinRM/RemotePowerShell (Over SSL)
308 | $portsToCheck += 9389 # TCP:Active Directory Web Services (ADWS)
309 |
310 | ###
311 | # Loading Any Applicable/Required Libraries
312 | ###
313 | # N.A.
314 |
315 | ###
316 | # Execute Any Additional Actions Required For The Script To Run Successfully
317 | ###
318 | # N.A.
319 |
320 | ###
321 | # Start Of Script
322 | ###
323 | ### Presentation Of Script Header
324 | writeLog -dataToLog ""
325 | writeLog -dataToLog " **********************************************************" -lineType "MAINHEADER"
326 | writeLog -dataToLog " * *" -lineType "MAINHEADER"
327 | writeLog -dataToLog " * --> Check Connectivity Targeted DCs <-- *" -lineType "MAINHEADER"
328 | writeLog -dataToLog " * *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
329 | writeLog -dataToLog " * Written By: Jorge de Almeida Pinto [MVP-EMS] *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
330 | writeLog -dataToLog " * *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
331 | writeLog -dataToLog " * BLOG: Jorge's Quest For Knowledge *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
332 | writeLog -dataToLog " * (URL: http://jorgequestforknowledge.wordpress.com/) *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
333 | writeLog -dataToLog " * *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
334 | writeLog -dataToLog " * $version *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
335 | writeLog -dataToLog " * *" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
336 | writeLog -dataToLog " **********************************************************" -lineType "MAINHEADER" -logFileOnly $false -noDateTimeInLogLine $false
337 | writeLog -dataToLog ""
338 |
339 | writeLog -dataToLog "" -lineType ""
340 | writeLog -dataToLog "Date/Time..................: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -lineType ""
341 | writeLog -dataToLog "" -lineType ""
342 | writeLog -dataToLog "TimeOut....................: $timeOut" -lineType ""
343 | writeLog -dataToLog "" -lineType ""
344 | writeLog -dataToLog "Local Computer FQDN........: $localComputerFQDN" -lineType ""
345 | Try {
346 | $localComputerIPAddress = ([System.Net.Dns]::GetHostEntry($localComputerFQDN)).AddressList.IPAddressToString
347 | } Catch {
348 | $localComputerIPAddress = "ERROR"
349 | }
350 | writeLog -dataToLog "Local Computer IP Address..: $($localComputerIPAddress -join ', ')" -lineType ""
351 | writeLog -dataToLog "" -lineType ""
352 | writeLog -dataToLog "Ports To Check.............:" -lineType ""
353 | $portsToCheck | ForEach-Object {
354 | writeLog -dataToLog " .............: $($_.ToString())" -lineType ""
355 | }
356 | writeLog -dataToLog "" -lineType ""
357 | writeLog -dataToLog "AD Forest FQDN.............: $adForestFQDN" -lineType ""
358 | writeLog -dataToLog "Root AD Domain NC DN.......: $adForestNCDN" -lineType ""
359 | writeLog -dataToLog "RWDC FQDN..................: $adForestRWDCFQDN" -lineType ""
360 | writeLog -dataToLog "" -lineType ""
361 | writeLog -dataToLog "Log File Path..............: $logFilePath" -lineType ""
362 | writeLog -dataToLog "" -lineType ""
363 |
364 | $dsDirSearcherDCs = New-Object DirectoryServices.DirectorySearcher([ADSI]"")
365 | $dsDirSearcherDCs.SearchRoot = "LDAP://$adForestRWDCFQDN/CN=Sites,CN=Configuration,$adForestNCDN"
366 | $dsDirSearcherDCs.SearchScope = "Subtree"
367 | $dsDirSearcherDCs.Filter = "(objectClass=nTDSDSA)"
368 | [void]($dsDirSearcherDCs.PropertiesToLoad.Add("distinguishedName"))
369 | [void]($dsDirSearcherDCs.PropertiesToLoad.Add("msDS-isGC"))
370 | $allNTDSDsaInADForest = ($dsDirSearcherDCs.FindAll()).Properties.distinguishedname
371 | $allSrvObjsInADForest = $allNTDSDsaInADForest.Replace("CN=NTDS Settings,","")
372 | $numDCs = ($allSrvObjsInADForest | Measure-Object).Count
373 | $resultsDCList = @()
374 | $i = 0
375 | $allSrvObjsInADForest | ForEach-Object {
376 | $i++
377 | $srvObject = [ADSI]"LDAP://$adForestRWDCFQDN/$($_)"
378 | $dnsHostName = $srvObject.Properties.dNSHostName[0]
379 | Try {
380 | $ipAddress = ([System.Net.Dns]::GetHostEntry($dnsHostName)).AddressList.IPAddressToString
381 | } Catch {
382 | $ipAddress = "ERROR"
383 | }
384 | writeLog -dataToLog "Testing DC '$dnsHostName' (IP Address: $ipAddress) ($($i.ToString().PadLeft($($numDCs.ToString().Length),'0')) Of $numDCs)..." -lineType ""
385 | $dcResult = New-Object -TypeName System.Object
386 | $dcResult | Add-Member -MemberType NoteProperty -Name "Nr" -Value $($i.ToString().PadLeft($($numDCs.ToString().Length),'0'))
387 | $dcResult | Add-Member -MemberType NoteProperty -Name "Host Name" -Value $dnsHostName
388 | $dcResult | Add-Member -MemberType NoteProperty -Name "IP Address" -Value $ipAddress
389 | $portsToCheck | ForEach-Object {
390 | $testResult = $null
391 | $testResult = portConnectionCheck -serverIPOrFQDN $dnsHostName -port $($_) -timeout $timeOut
392 | If ($testResult -eq "SUCCESS") {
393 | writeLog -dataToLog " > Port '$($_)' - $testResult..." -lineType "SUCCESS"
394 | } Else {
395 | writeLog -dataToLog " > Port '$($_)' - $testResult..." -lineType "ERROR"
396 | }
397 | $dcResult | Add-Member -MemberType NoteProperty -Name "Port$($_)" -Value $testResult
398 | }
399 | $resultsDCList += $dcResult
400 | writeLog -dataToLog "" -lineType ""
401 | }
402 | writeLog -dataToLog "$($resultsDCList | Format-Table * -Wrap -AutoSize | Out-String)" -lineType ""
403 |
404 | writeLog -dataToLog "" -lineType ""
405 | writeLog -dataToLog "Log File Path..............: $logFilePath" -lineType ""
406 | writeLog -dataToLog "" -lineType ""
--------------------------------------------------------------------------------
/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.md:
--------------------------------------------------------------------------------
1 | # SCRIPT: Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence
2 |
3 | ## AUTHOR/FEEDBACK
4 |
5 | * Written By: Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]
6 | * Re-Written By: N.A.
7 | * Company: IAMTEC >> Identity | Security | Recovery [https://www.iamtec.eu/]
8 | * Blog: Jorge's Quest For Knowledge [http://jorgequestforknowledge.wordpress.com/]
9 | * For Feedback/Questions: scripts DOT gallery AT iamtec.eu
10 | * Please Describe Your Scenario As Best As Possible With As Much Detail As Possible.
11 | * If Applicable Describe What Does and/Or Does Not Work.
12 | * If Applicable Describe What Should Be/Work Different And Explain Why/How.
13 | * Please Add Screendumps.
14 |
15 | ## ORIGINAL SOURCE(S)
16 |
17 | *
18 |
19 | ## DISCLAIMER
20 |
21 | * The script is FREEWARE, you are free to distribute/update it, but always refer to the original source(s) as the location where you got it
22 | * This script is furnished "AS IS". NO warranty is expressed or implied!
23 | * I HAVE NOT tested it in every scenario or environment
24 | * ALWAYS TEST FIRST in lab environment to see if it meets your needs!
25 | * Use this script at YOUR OWN RISK! YOU ARE RESPONSIBLE FOR ANY OUTCOME/RESULT BY USING THIS SCRIPT!
26 | * I DO NOT warrant this script to be fit for any purpose, use or environment!
27 | * I have tried to check everything that needed to be checked, but I DO NOT guarantee the script does not have bugs!
28 | * I DO NOT guarantee the script will not damage or destroy your system(s), environment or anything else due to improper use or bugs!
29 | * I DO NOT accept liability in any way when making mistakes, use the script wrong or in any other way where damage is caused to your environment/systems!
30 | * If you do not accept these terms DO NOT use the script in any way and delete it immediately!
31 |
32 | ## KNOWN ISSUES/BUGS
33 |
34 | * When migrating SYSVOL Replication from NTFRS to DFSR, the NTFRS Replica Set for the SYSVOL might still show up with no replication mechanism specified. This will resolve itself as soon as ALL DCs have reached the ELIMINATED state!
35 | * Without additional tooling on every Replica Member, it is not possible to determine when the file arrived at a specific Replica Member. The calculation is therefore done when the script "sees" the file on a Replica Member
36 | * The content of the HTML file in the browser might suddenly appear to be blank. This might resolve by itself during the refresh or when the admin refreshes manually
37 | * Reachability of a certain replica member depends on the required port being open, AND the speed a replica member responds back. If the configured timeout is too low while a high latency is experienced, increase the configured timeout by using the XML configuration file
38 |
39 | ## RELEASE NOTES
40 |
41 | * v0.9, 2024-12-11, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
42 |
43 | * Improved User Experience: Changed the layout of the output on screen to display a summary of the progress.
44 | * Improved User Experience: Added URL for documentation to the ORIGINAL SOURCE(S) section above
45 | * Improved User Experience: Support for an XML file to specify environment specific connection parameters. At the same time this also allows upgrades/updates of the script without loosing those specify environment specific connection parameters
46 | * Improved User Experience: For a more detailed view of the progress, that information will automatically be displayed through an HTML file in a browser and refreshed every 5 seconds to display any changes.
47 | * Code Improvement: Implemented StrictMode Latest Version (Tested On PoSH 5.x And 7.x)
48 | * Code Improvement: Replaced "Get-WmiObject" with "Get-CimInstance" to also support PowerShell 7.x
49 | * New Feature: Added the function "showProgress" to display the progress of an action
50 | * New Feature: Added parameter to skip opening the HTML in a browser to support automation
51 |
52 | * v0.8, 2024-09-03, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
53 |
54 | * Code Improvement: DFSR - For scenarios where metadata cleanup was not fully complete where also the "msDFSR-Member" is cleaned, an additional check is added to make sure the "msDFSR-Member" object has a value for "msDFSR-ComputerReference"
55 | * Code Improvement: NTFRS - For scenarios where metadata cleanup was not fully complete where also the "nTFRSMember" is cleaned, an additional check is added to make sure the "nTFRSMember" object has a value for "frsComputerReference"
56 | * Code Improvement: Better/improved detection of replication mechanism used for SYSVOL
57 | * Code Improvement: Redefined reachability specifically for WinRM and SMB
58 | * Improved User Experience: Added a check to determine if orphaned metadata exists of replication members for either NTFRS and DFS-R
59 | * Improved User Experience: Faster processing due to paralellel processing through RunSpaces. (MAJOR CHANGE and WILL IMPACT CPU/RAM usage when checking against many members!)
60 | To configure the behavior of the processing in the Runspaces, review and update as needed the variables "$runspacePoolMinThreads", "$runspacePoolMaxThreads" And "$delayInMilliSecondsBetweenChecks"
61 | Inspired by:
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | * Improved User Experience: Added at the beginning the output of the command line and all parameters used
70 | * New Feature: Added the function "checkDNExistence" to check if an object exists or not
71 | * New Feature: SYSVOL Repl through NTFRS only is supported, SYSVOL Repl through DFSR only is supported and now also SYSVOL Repl through both NTFRS and DFSR (only when migrating, in either the PREPARED or REDIRECTED state) is supported
72 | * Bug Fix: Added forgotten parameter to automatically cleanup orphaned canary files when found
73 | * Bug Fix: The value specified for the parameter targetReplMember now is used
74 | * Bug Fix: Corrected the name of the log that is created
75 | * New Feature: Added parameter to skip cleaning of orphaned canary files when found
76 | * New Feature: Added variable that specifies the delay in milliseconds between the checks for each member. The default is 0, which means NO DELAY and go for it!
77 | * New Feature: Added a parameter to allow the export of the results into a CSV
78 |
79 | * v0.7, 2024-07-30, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
80 |
81 | * Bug Fix: Fixed case sensitivity bug when specifying a DFR Replicated Folder Name through the command line
82 | * Bug Fix: Fixed case sensitivity bug when specifying a Domain FQDN through the command line
83 |
84 | * v0.6, 2024-02-06, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
85 |
86 | * Code Improvement: Changed the function "getDFSRReplGroupMembers" to not use a GC, but instead use a RWDC from the respective AD domain of the object that is being looked for
87 | * Code Improvement: When discovering a member, added a check to choose a member with a writable copy of the replicated folder
88 | * Improved User Experience: Added a check to determine if there are Temporary Canary Object leftovers from previous executions of the script that were not cleaned up because the script was aborted or it crashed
89 | * Improved User Experience: Changed the timing column from "Time" to "TimeDiscvrd" (Time Discovered) which specifies how much time it took to find/see the file on the member of the replicated folder
90 | * Improved User Experience: The AD domain list presented is now consistently presented in the same order
91 | * Bug Fix: Fixed the unc path for the folder when SYSVOL is still using NTFRS. Temporary Canary File is now created in the Scripts folder (SYSVOL only!)
92 | * Bug Fix: When not using SYSVOL as replicated folder, fixed the Member to target for checking the existence of the Temporary Canary File
93 | * Bug Fix: Changed the variable name of the unc path for the folder on the source from $uncPathFolder to $uncPathFolderSource, to also target the correct (source) Member for cleanup of the file
94 |
95 | * v0.5, 2024-01-31, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
96 |
97 | * Script Improvement: Complete rewrite of the script
98 | * New Feature: Parameters added to support automation
99 | * New Feature: Logging Function
100 | * New Feature: Support for all replicated folders (SYSVOL and Custom), replicated either through NTFRS or DFSR
101 | * New Feature: File count across each member (enabled by default), can be disabled with parameter
102 | * Code Improvement: As target member use specific role owner hosting the PDC FSMO (SYSVOL only!), disccovered member, specific member
103 |
104 | * v0.4, 2014-02-11, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
105 | * Code Improvement: Added additional logic to determine if a DC is either an RWDC or RODC when it fails using the first logic and changed the layout a little bit
106 |
107 | * v0.3, 2014-02-09, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
108 | * Bug Fix: Solved a bug with regards to the detection/location of RWDCs and RODCs
109 |
110 | * v0.2, 2014-02-01, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
111 |
112 | * New Feature: Updated to also work on W2K3
113 | * New Feature: Added STOP option
114 | * Code Improvement: Added few extra columns to output extra info of DCs,
115 | * Code Improvement: Better detection of unavailable DCs/GCs
116 | * Code Improvement: Added screen adjustment section
117 |
118 | * v0.1, 2013-03-02, Jorge de Almeida Pinto [MVP Security / Lead Identity/Security Architect]:
119 | * Initial version of the script
120 |
121 | ## SYNOPSIS/DESCRIPTION
122 |
123 | This PoSH Script Checks The File Replication Latency/Convergence For Replicated Folders (SYSVOL And Custom) Using Either NTFRS Or DFSR.
124 |
125 | This PoSH script provides the following functions:
126 |
127 | * It executes all checks in parallel at the same time against all replica members in scope.
128 | * It executes on a per replicated folder basis. For multiple replicated folder use automation with parameters.
129 | * For automation, it is possible to define the FQDN of the AD Domain to target, the name of the replica set (NTFRS) or the name of the replicated folder (DFSR) within that AD domain, and the member to use as the source
130 | member to create the temoporary canary file on.
131 | * It supports non-interacive mode through automation with parameters, or interactive mode.
132 | * It supports file replication convergence check for any replica set (NTFRS) or replicated folder (DFSR) within an AD forest.
133 | * Connectivity check to replica members through TCP:WinRM/5985 for the purpose of counting files locally on the replica member
134 | * Connectivity check to replica members through TCP:SMB/5985 for the purpose of checking the existance of the canary file
135 | * As the source member, it is possible to:
136 | * Use the FSMO of the AD Domain, when it concerns the SYSVOL only
137 | * Use a discovered member (best effort)
138 | * Specify the FQDN of a member that hosts the replica set (NTFRS) or the replicated folder (DFSR)
139 | * For the temporary canary file:
140 | * Initially created on the source member and deleted from the source member at the end
141 | * Name = _fileReplConvergenceCheckTempFile_yyyyMMddHHmmss (e.g. _fileReplConvergenceCheckTempFile_20240102030405)
142 | * Content = ...!!!...TEMP FILE TO TEST REPLICATION LATENCY/CONVERGENCE FOR REPLICATED FOLDER <REPLICA SET NAME (NTFRS) OR REPLICATED FOLDER NAME (DFSR)> IN AD DOMAIN <AD DOMAIN FQDN> USING MEMBER <SOURCE MEMBER> AS THE SOURCE MEMBER...!!!...
143 | * Container:
144 | * For custom replicated folders => Folder = At the root of the folder
145 | * For SYSVOL => Folder = "<SYSVOL LOCAL PATH>\Scripts"
146 | * In the PowerShell command prompt window the global progress is displayed. The same thing is also logged to a log file
147 | * When a default browser is available/configured, the generated HTML file will be opened and automatically refreshed every 5 seconds as the script progresses. This HTML file displays the replica member specific state/result
148 | * It checks if specified replica set (NTFRS) or replicated folder (DFSR) exists. If not, the script aborts.
149 | * It checks if specified member exists. If not, the script aborts.
150 | * At the end it checks if any Temporary Canary Files exist from previous execution of the script and offers to clean up (In the chosen Replicated Folder only!).
151 | * Disjoint namespaces and discontiguous namespaces are supported.
152 | * The script uses default values for specific connection parameters. If those do not meet expectation, an XML configuration file can be used with custom values.
153 | * For the specific replicated folder, the script also checks if any remaining canary files exists from previous script executions that either failed or were aborted. It provides the option to also clean those or not.
154 | Through a parameter it allows to default to always clean previous canary files when found. This behavior is ignored when the parameter to skip the check of previous canary files is used
155 | * In addition to displaying the end results on screen, it is also possible to export those end results to a CSV file
156 | * Through a parameter it is possible to skip the check of previous canary files
157 | * During interactive mode, after specifying the source member, it will count the files in the replicated folder on every member by default. This can be disabled through a parameter.
158 | * Through a parameter it is possible to not open the generated HTML in the default browser
159 | * The script supports automation by using parameters with pre-specified details of the targeted Domain FQDN, the targeted Replicated Folder and the targeted source Replica Member
160 |
161 | ## PARAMETER(S)
162 |
163 | cleanupOrhanedCanaryFiles
164 |
165 | * With this parameter it is possible to automatically cleanup orphaned canary files when found
166 |
167 | exportResultsToCSV
168 |
169 | * With this parameter it is possible to export the results to a CSV file in addition of displaying it on screen on in the log file
170 |
171 | skipCheckForOrphanedCanaryFiles
172 |
173 | * With this parameter it is possible not to check for orphaned canary files
174 |
175 | skipFileCount
176 |
177 | * With this parameter it is possible not count files in the replicated folder on every member
178 |
179 | skipOpenHTMLFileInBrowser
180 |
181 | * With this parameter it is possible to not open the HTML file in the default browser
182 |
183 | targetDomainFQDN
184 |
185 | * With this parameter it is possible to specify the FQDN of an AD domain to target for File Replication Convergence/Latency check against a chosen replica set (NTFRS) or the replicated folder (DFSR) within that AD domain
186 |
187 | targetReplFolder
188 |
189 | * With this parameter it is possible to specify the name of the replica set (NTFRS) or the replicated folder (DFSR) within the chosen AD domain to target for the File Replication Convergence/Latency check
190 |
191 | targetReplMember
192 |
193 | * With this parameter it is possible to specify the member to use to create the temporary canary file on. Options that are available for this are "Fsmo" (SYSVOL only!), "Discover" or the FQDN of a member
194 |
195 | ## EXAMPLE(S)
196 |
197 | Check The File Replication Convergence/Latency Using Interactive Mode (Including File Count)
198 |
199 | ``` powershell
200 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1
201 | ```
202 |
203 | Check The File Replication Convergence/Latency Using Interactive Mode (Excluding File Count)
204 |
205 | ``` powershell
206 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -skipFileCount
207 | ```
208 |
209 | Check The File Replication Convergence/Latency Using Automated Mode For The SYSVOL Replicated Through NTFRS Using The Fsmo Role Owner As The Source Member To Create The Temporary Canary File On (Including File Count)
210 |
211 | ``` powershell
212 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "Domain System Volume (SYSVOL share)" -targetReplMember Fsmo
213 | ```
214 |
215 | Check The File Replication Convergence/Latency Using Automated Mode For The SYSVOL Replicated Through DFSR Using The Fsmo Role Owner As The Source Member To Create The Temporary Canary File On (Including File Count)
216 |
217 | ``` powershell
218 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "SYSVOL Share" -targetReplMember Fsmo
219 | ```
220 |
221 | Check The File Replication Convergence/Latency Using Automated Mode For The Replicated Folder "LPPStoreForAD" Using A Discovered Member As The Source Member To Create The Temporary Canary File On (Including File Count)
222 |
223 | ``` powershell
224 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "LPPStoreForAD" -targetRWDC Discover
225 | ```
226 |
227 | Check The File Replication Convergence/Latency Using Automated Mode For The Replicated Folder "LPPStoreForAD" Using A Specific Member As The Source Member To Create The Temporary Canary File On (Including File Count)
228 |
229 | ``` powershell
230 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "LPPStoreForAD" -targetRWDC "R1FSRWDC1.IAMTEC.NET"
231 | ```
232 |
233 | Check The File Replication Convergence/Latency Using Automated Mode For The SYSVOL Replicated Through NTFRS Using The Fsmo Role Owner As The Source Member To Create The Temporary Canary File On (Excluding File Count)
234 |
235 | ``` powershell
236 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "Domain System Volume (SYSVOL share)" -targetReplMember Fsmo -skipFileCount
237 | ```
238 |
239 | Check The File Replication Convergence/Latency Using Automated Mode For The SYSVOL Replicated Through DFSR Using The Fsmo Role Owner As The Source Member To Create The Temporary Canary File On (Excluding File Count)
240 |
241 | ``` powershell
242 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "SYSVOL Share" -targetReplMember Fsmo -skipFileCount
243 | ```
244 |
245 | Check The File Replication Convergence/Latency Using Automated Mode For The Replicated Folder "LPPStoreForAD" Using A Discovered Member As The Source Member To Create The Temporary Canary File On (Excluding File Count)
246 |
247 | ``` powershell
248 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "LPPStoreForAD" -targetRWDC Discover -skipFileCount
249 | ```
250 |
251 | Check The File Replication Convergence/Latency Using Automated Mode For The Replicated Folder "LPPStoreForAD" Using A Specific Member As The Source Member To Create The Temporary Canary File On (Excluding File Count)
252 |
253 | ``` powershell
254 | .\Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.ps1 -targetDomainFQDN IAMTEC.NET -targetReplFolder "LPPStoreForAD" -targetRWDC "R1FSRWDC1.IAMTEC.NET" -skipFileCount
255 | ```
256 |
257 | ## NOTES
258 |
259 | * To execute this script, the account running the script MUST have the permissions to create and delete the file in the local folder of the source member through the drive share (C$, D$, etc). Being a local admin on all
260 | the member allows, the creation, deletion and monitoring of the file
261 | * The credentials used are the credentials of the logged on account. It is not possible to provided other credentials. Other credentials could maybe be used through RUNAS /NETONLY /USER
262 | * No check is done for the required permissions. The script simply assumes the required permissions are available. If not, errors will occur
263 | * No PowerShell modules are needed to use this script
264 | * For the SYSVOL, it only works correctly when either using NTFRS, or DFSR in a completed state!
265 | * Admin shares MUST be enabled
266 | * For File Count, WinRM must be possible against the remote machines (TCP:WinRM/5985)
267 | * Yes, I'm aware, there is duplicate code to support both NTFRS and DFSR. This was the easiest way to support both without too much complexity. It also allows to remove it easily when NTFRS cannot be used anymore
268 | * Detailed NTFRS Info:
269 | * Script Has StrictMode Enabled For Latest Version - Tested With PowerShell 7.4.5
270 | * Reachbility for counting files locally on the member within the replicated folder is determined by checking against the required port (WinRM HTTP Transport Port TCP:5985 for Replica Members) and if the member responds
271 | fast enough before the defined connection timeout
272 | * Reachbility for checking the existance of the canary file on the member within the replicated folder is determined by checking against the required port (SMB Over TCP/IP TCP:445 for Replica Members) and if the member
273 | responds fast enough before the defined connection timeout
274 | * The XML file for the environment specific oonnection parameters should have the exact same name as the script and must be in the same folder as the script. If the script is renamed, the XML should be renamed accordingly.
275 | For example, if the script is called "Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_v09.ps1", the XML file should be called "Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_v09.xml".
276 | When a decision is made to use the XML Configuration File, then ALL connection parameters MUST be defined in it. The structure of the XML file is:
277 |
278 | ```XML
279 |
280 |
281 |
282 |
283 | TRUE_OR_FALSE
284 |
285 |
286 | REPLACE_WITH_NUMERIC_VALUE
287 |
288 |
289 | REPLACE_WITH_NUMERIC_VALUE
290 |
291 |
292 | REPLACE_WITH_NUMERIC_VALUE
293 |
294 |
295 | REPLACE_WITH_NUMERIC_VALUE
296 |
297 |
298 | REPLACE_WITH_NUMERIC_VALUE
299 |
300 |
301 | ```
302 |
303 | ## SCREENSHOTS (NEW WAY OF EXECUTION AND PROCESSING!)
304 |
305 | 
306 |
307 | 
308 |
309 | 
310 |
311 | 
312 |
313 | 
314 |
315 | 
316 |
317 | 
318 |
319 | 
320 |
321 | 
322 |
323 | 
324 |
325 | 
326 |
327 | 
328 |
329 | 
330 |
331 | 
332 |
333 | 
334 |
335 | 
336 |
337 | 
338 |
339 | 
340 |
341 | 
342 |
343 | ## SCREENSHOTS (PREVIOUS WAY OF EXECUTION AND PROCESSING!)
344 |
345 | 
346 |
347 | 
348 |
349 | 
350 |
351 | 
352 |
353 | 
354 |
355 | 
356 |
357 | 
358 |
359 | 
360 |
361 | 
362 |
363 | 
364 |
365 | 
366 |
367 | 
368 |
369 | 
370 |
--------------------------------------------------------------------------------
/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FALSE
5 |
6 |
7 | 500
8 |
9 |
10 | 30
11 |
12 |
13 | 1
14 |
15 |
16 | 2048
17 |
18 |
19 | 500
20 |
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture01.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture02.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture03.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture04.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture05.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture06.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture07.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture08.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture09.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture10.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture11.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture12.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture13.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture14.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture15.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture16.png
--------------------------------------------------------------------------------
/Images/Check-AD-Replication-Latency-Convergence_Picture17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-AD-Replication-Latency-Convergence_Picture17.png
--------------------------------------------------------------------------------
/Images/Check-Connectivity-All-DCs-In-AD-Forest01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-Connectivity-All-DCs-In-AD-Forest01.png
--------------------------------------------------------------------------------
/Images/Check-Connectivity-All-DCs-In-AD-Forest02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-Connectivity-All-DCs-In-AD-Forest02.png
--------------------------------------------------------------------------------
/Images/Check-Connectivity-All-DCs-In-AD-Forest03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-Connectivity-All-DCs-In-AD-Forest03.png
--------------------------------------------------------------------------------
/Images/Check-Connectivity-All-DCs-In-AD-Forest04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-Connectivity-All-DCs-In-AD-Forest04.png
--------------------------------------------------------------------------------
/Images/Check-Connectivity-All-DCs-In-AD-Forest05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-Connectivity-All-DCs-In-AD-Forest05.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture14.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture15.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture16.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture17.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture18.png
--------------------------------------------------------------------------------
/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture19.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture01.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture02.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture03.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture04.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture05.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture06.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture07.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture08.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture09.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture10.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture11.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture12.png
--------------------------------------------------------------------------------
/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-AD-Replication-Latency-Convergence_Picture13.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture01.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture02.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture03.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture04.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture05.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture06.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture07.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture08.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture09.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture10.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture11.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture12.png
--------------------------------------------------------------------------------
/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Images/OLD_Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence_Picture13.png
--------------------------------------------------------------------------------
/Managing-ACEs-In-AD-Through-PowerShell.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjorz/Public-AD-Scripts/6b73209d696015fdd37e619ae1fbb013c99b0279/Managing-ACEs-In-AD-Through-PowerShell.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Public-AD-Scripts
2 |
3 | AD Scripts
4 |
5 | REMARK: To Open Links In Another TAB
6 |
7 | * On Windows: Press CTRL + Click The Link
8 | * On Windows: Press CTRL + Click The Link
9 | * On MacOS: Press CMD + Click The Link
10 |
11 | [SCRIPT: Check-AD-Replication-Latency-Convergence](Check-AD-Replication-Latency-Convergence.md)
12 |
13 | [SCRIPT: Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence](Check-SYSVOL-And-DFSR-And-NTFRS-Folders-Replication-Latency-Convergence.md)
14 |
--------------------------------------------------------------------------------
/Reset-KrbTgt-Password-For-RWDCs-And-RODCs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | REPLACE_WITH_MAIL_SERVER_FQDN
5 |
6 |
7 | REPLACE_WITH_MAIL_SERVER_SMTP_PORT_NUMERIC_VALUE
8 |
9 |
10 | TRUE_OR_FALSE
11 |
12 |
13 | IMPLICIT_OR_EXPLICIT
14 |
15 |
16 | LEAVE_EMPTY_OR_LEAVE_AS_IS_OR_REPLACE_WITH_USERNAME_IF_USED
17 | LEAVE_EMPTY_OR_LEAVE_AS_IS_OR_REPLACE_WITH_PASSWORD_IF_USED
18 |
19 |
20 | KrbTgt Password Reset Result
21 |
22 |
23 | High
24 |
25 |
26 |
27 | <!DOCTYPE html>
28 | <html>
29 | <head>
30 | <title>KrbTgt_Password_Reset</title>
31 | <style type="text/css">
32 | </style>
33 | </head>
34 | <body>
35 | <B><P align="center" style="font-size: 24pt; font-family: Arial Narrow, sans-serif; color: red">!!! ATTENTION | FYI - ACTION REQUIRED !!!</P></B>
36 | <hr size=2 width="95%" align=center>
37 | <BR>
38 | <P style="font-size: 12pt; font-family: Arial Narrow, sans-serif;">Hello,</P>
39 | <BR>
40 | <P style="font-size: 12pt; font-family: Arial Narrow, sans-serif;">Please review the attached log file.</P>
41 | <BR>
42 | <P style="font-size: 12pt; font-family: Arial Narrow, sans-serif;">Best regards</P>
43 | </body>
44 | </html>
45 |
46 |
47 | sender_Mail_Address@company.com
48 |
49 |
50 | recipient_To_MailAddress@company.com
51 |
52 |
53 |
54 |
55 | recipient_Cc_MailAddress_1@company.com
56 | recipient_Cc_MailAddress_2@company.com
57 |
58 |
59 |
60 | OFF
61 | OFF
62 |
63 |
64 |
65 | REPLACE_WITH_FULL_FOLDER_PATH_TO_COMPILED_DLL_FILE\Cpi.Net.SecureMail.dll
66 |
67 |
68 | STORE_OR_PFX
69 | STORE_OR_CER
70 |
71 |
72 | LEAVE_EMPTY_OR_LEAVE_AS_IS_OR_REPLACE_WITH_THUMBPRINT_IF_USED
73 | LEAVE_EMPTY_OR_LEAVE_AS_IS_OR_REPLACE_WITH_THUMBPRINT_IF_USED
74 |
75 |
76 | REPLACE_WITH_FULL_FOLDER_PATH_TO_PFX_FILE\cert.pfx
77 | REPLACE_WITH_FULL_FOLDER_PATH_TO_CER_FILE\cert.cer
78 |
79 |
80 | LEAVE_EMPTY_OR_LEAVE_AS_IS_OR_REPLACE_WITH_PFX_PASSWORD_IF_USED
81 |
--------------------------------------------------------------------------------
/Retrieve-List-Of-Conflicting-Objects.ps1:
--------------------------------------------------------------------------------
1 | # Clear The Screen
2 | Clear-Host
3 |
4 | # Checking Number Of Arguments
5 | $numArgs = $args.count
6 | $arg0 = $args[0]
7 |
8 | # Discovering A GC Retrieving Its DNS HostName
9 | $dnsHostNameGC = (Get-ADDomainController -Service GlobalCatalog -Discover:$true).HostName[0]
10 | $gcHostPort = $dnsHostNameGC + ":3268"
11 | $dsContextDC = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("DirectoryServer",$dnsHostNameGC)
12 | $dc = [System.DirectoryServices.ActiveDirectory.DomainController]::GetDomainController($dsContextDC)
13 |
14 | # General Execution Of Script
15 | If ($numArgs -eq 0) {
16 | $listOfConflictingObjects = Get-ADObject -server $gcHostPort -LDAPFilter '(name=*CNF:*)'
17 | }
18 | If ($numArgs -eq 1) {
19 | If ($arg0.ToLower() -eq "computer") {
20 | $listOfConflictingObjects = Get-ADComputer -server $gcHostPort -LDAPFilter '(name=*CNF:*)' -Properties pwdLastSet
21 | }
22 | If ($arg0.ToLower() -eq "user") {
23 | $listOfConflictingObjects = Get-ADUser -server $gcHostPort -LDAPFilter '(name=*CNF:*)' -Properties pwdLastSet
24 | }
25 | }
26 | If ($listOfConflictingObjects -ne $null) {
27 | $listOfDuplicates = @()
28 | $listOfConflictingObjects | %{
29 | $objCNF = $_
30 | $dnCNFobj = $objCNF.DistinguishedName
31 | $classCNFobj = $_.ObjectClass
32 | $guidCNFobj = $_.ObjectGUID
33 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
34 | $sAMAccountCNFobj = $_.SamAccountName
35 | $pwdLastSetCNFobj = $_.pwdLastSet
36 | If ($pwdLastSetCNFobj -ne $null){
37 | $pwdLastSetCNFobj = Get-Date -Date ([DateTime]::FromFileTime([Int64]::Parse($pwdLastSetCNFobj))) -Format "yyyy-MM-dd HH:mm:ss"
38 | } Else {
39 | $pwdLastSetCNFobj = "---"
40 | }
41 | }
42 | $objCNFMetadata = $dc.GetReplicationMetadata($dnCNFobj)
43 | $objCNFOrigSrv = $objCNFMetadata | %{($_.objectclass).OriginatingServer}
44 | $objCNFOrigTime = $objCNFMetadata | %{($_.objectclass).LastOriginatingChangeTime}
45 | $dnORGobj = $dnCNFobj.Substring(0,$dnCNFobj.IndexOf("\")) + $dnCNFobj.Substring($dnCNFobj.IndexOf(","))
46 | If ($numArgs -eq 0) {
47 | $objORG = Get-ADObject -server $gcHostPort -Identity $dnORGobj
48 | }
49 | If ($numArgs -eq 1) {
50 | If ($arg0.ToLower() -eq "computer") {
51 | $objORG = Get-ADComputer -server $gcHostPort -Identity $dnORGobj -Properties pwdLastSet
52 | }
53 | If ($arg0.ToLower() -eq "user") {
54 | $objORG = Get-ADUser -server $gcHostPort -Identity $dnORGobj -Properties pwdLastSet
55 | }
56 | }
57 | $dnORGobj = $null
58 | $classORGobj = $null
59 | $guidORGobj = $null
60 | $sAMAccountORGobj = $null
61 | $pwdLastSetORGobj = $null
62 | $objORGMetadata = $null
63 | If ($objORG -ne $null) {
64 | $dnORGobj = $objORG.DistinguishedName
65 | $classORGobj = $objORG.ObjectClass
66 | $guidORGobj = $objORG.ObjectGUID
67 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
68 | $sAMAccountORGobj = $objORG.SamAccountName
69 | $pwdLastSetORGobj = $objORG.pwdLastSet
70 | If ($pwdLastSetORGobj -ne $null){
71 | $pwdLastSetORGobj = Get-Date -Date ([DateTime]::FromFileTime([Int64]::Parse($pwdLastSetORGobj))) -Format "yyyy-MM-dd HH:mm:ss"
72 | } Else {
73 | $pwdLastSetORGobj = "---"
74 | }
75 | }
76 | $objORGMetadata = $dc.GetReplicationMetadata($dnORGobj)
77 | $objORGOrigSrv = $objORGMetadata | %{($_.objectclass).OriginatingServer}
78 | $objORGOrigTime = $objORGMetadata | %{($_.objectclass).LastOriginatingChangeTime}
79 | } Else {
80 | $dnORGobj = "Does Not Exit"
81 | $classORGobj = "Does Not Exit"
82 | $guidORGobj = "Does Not Exit"
83 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
84 | $sAMAccountORGobj = "Does Not Exit"
85 | $pwdLastSetORGobj = "Does Not Exit"
86 | }
87 | $objORGOrigSrv = "Does Not Exit"
88 | $objORGOrigTime = "Does Not Exit"
89 | }
90 |
91 | If ($numArgs -eq 0) {
92 | $adObj = "" | Select "> > >DN (CNF)..........","objectClass (CNF)......","objectGUID (CNF).......","Originating DC (CNF)...","Originating Time (CNF).","> > >DN (ORG)..........","objectClass (ORG)......","objectGUID (ORG).......","Originating DC (ORG)...","Originating Time (ORG)."
93 | }
94 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
95 | $adObj = "" | Select "> > >DN (CNF)..........","objectClass (CNF)......","objectGUID (CNF).......","Account Name (CNF).....","PWD Last Set (CNF).....","Originating DC (CNF)...","Originating Time (CNF).","> > >DN (ORG)..........","objectClass (ORG)......","objectGUID (ORG).......","Account Name (ORG).....","PWD Last Set (ORG).....","Originating DC (ORG)...","Originating Time (ORG)."
96 | }
97 | $adObj."> > >DN (CNF).........." = $dnCNFobj
98 | $adObj."objectClass (CNF)......" = $classCNFobj
99 | $adObj."objectGUID (CNF)......." = $guidCNFobj
100 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
101 | $adObj."Account Name (CNF)....." = $sAMAccountCNFobj
102 | $adObj."PWD Last Set (CNF)....." = $pwdLastSetCNFobj
103 | }
104 | $adObj."Originating DC (CNF)..." = $objCNFOrigSrv
105 | $adObj."Originating Time (CNF)." = $objCNFOrigTime
106 | $adObj."> > >DN (ORG).........." = $dnORGobj
107 | $adObj."objectClass (ORG)......" = $classORGobj
108 | $adObj."objectGUID (ORG)......." = $guidORGobj
109 | If ($numArgs -eq 1 -And ($arg0.ToLower() -eq "computer" -Or $arg0.ToLower() -eq "user")) {
110 | $adObj."Account Name (ORG)....." = $sAMAccountORGobj
111 | $adObj."PWD Last Set (ORG)....." = $pwdLastSetORGobj
112 | }
113 | $adObj."Originating DC (ORG)..." = $objORGOrigSrv
114 | $adObj."Originating Time (ORG)." = $objORGOrigTime
115 |
116 | $listOfDuplicates += $adObj
117 | }
118 | Write-Host ""
119 | If ($numArgs -eq 0) {
120 | Write-Host "LIST OF DUPLICATE/CONFLICTING OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan
121 | }
122 | If ($numArgs -eq 1 -And $arg0.ToLower() -eq "computer") {
123 | Write-Host "LIST OF DUPLICATE/CONFLICTING COMPUTER OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan
124 | }
125 | If ($numArgs -eq 1 -And $arg0.ToLower() -eq "user") {
126 | Write-Host "LIST OF DUPLICATE/CONFLICTING USER OBJECTS IN THE AD FOREST" -Foregroundcolor Cyan
127 | }
128 | $listOfDuplicates | FL
129 | } Else {
130 | Write-Host "NO DUPLICATE/CONFLICTING OBJECTS DETECTED IN THE AD FOREST" -Foregroundcolor Green
131 | }
--------------------------------------------------------------------------------
/Scan-And-Check-All-Accounts-In-AD-Forest_01_Basic-Info.ps1:
--------------------------------------------------------------------------------
1 | ### Abstract: This PoSH Script Scans And Checks All Accounts In The AD Forest And Creates A CSV Report And Outputs To GridView
2 | ### Written by: Jorge de Almeida Pinto [MVP-EMS]
3 | ### BLOG: http://jorgequestforknowledge.wordpress.com/
4 | ###
5 | ### 2019-10-26: Initial version of the script (v0.1)
6 | ###
7 |
8 | <#
9 | .SYNOPSIS
10 | .DESCRIPTION
11 | This PoSH Script Leverages LDAP Queries To:
12 | * Generate CSV Report With The Results. For every account (user, computer, gMSA, inetOrgPerson), the following is gathered and listed
13 | * Domain FQDN (e.g. 'IAMTEC.NET')
14 | * Domain NBT (e.g. 'IAMTEC')
15 | * Domain DN (e.g. 'DC=IAMTEC,DC=NET')
16 | * Sam Account Name (e.g. 'jorge')
17 | * Account Name (e.g. 'IAMTEC\jorge')
18 | * Account Type (computer, inetOrgPerson, msDS-GroupManagedServiceAccount, trust (user), user)
19 | * User Principal Name (e.g. 'jorge@iamtec.nl')
20 | * Display Name (e.g. Jorge de Almeida Pinto)
21 | * Enabled (e.g. TRUE or FALSE)
22 | * Locked (e.g. TRUE - At: or FALSE - Never Locked or FALSE - Has Been Locked Before)
23 | * Account Expires On (e.g. or NEVER)
24 | * Pwd Last Set On (e.g. or "Must Chng At Next Logon")
25 | * Pwd Never Expires (e.g. TRUE or FALSE)
26 | * Last Logon Timestamp (e.g. or NEVER)
27 | * Last Logon (RWDC) (e.g. or NEVER Or NOT AVAILABLE (On '')) <-- THIS MEANS IT WILL QUERY EVERY DC (RWDC And RODC) In The AD Domain To Get The LastLogon Property From That DC!
28 |
29 | .EXAMPLE
30 | Scan/Check All Accounts In The AD Forest And Create The Report
31 |
32 | .\Scan-And-Check-All-Accounts-In-AD-Forest_01_Basic-Info.ps1
33 |
34 | .NOTES
35 | This script requires:
36 | * PowerShell Module: ActiveDirectory
37 | * Basic Permissions, Nothing Special!
38 | #>
39 |
40 | ### FUNCTION: Logging Data To The Log File
41 | Function Logging($dataToLog, $lineType) {
42 | $datetimeLogLine = "[" + $(Get-Date -format "yyyy-MM-dd HH:mm:ss") + "] : "
43 | Out-File -filepath "$logFilePath" -append -inputObject "$datetimeLogLine$dataToLog"
44 | #Write-Output($datetimeLogLine + $dataToLog)
45 | If ($lineType -eq $NULL) {
46 | Write-Host "$datetimeLogLine$dataToLog"
47 | }
48 | If ($lineType -eq "SUCCESS") {
49 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Green
50 | }
51 | If ($lineType -eq "ERROR") {
52 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
53 | }
54 | If ($lineType -eq "WARNING") {
55 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
56 | }
57 | If ($lineType -eq "HEADER") {
58 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Magenta
59 | }
60 | If ($lineType -eq "REMARK") {
61 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Cyan
62 | }
63 | }
64 |
65 | ### FUNCTION: Load Required PowerShell Modules
66 | Function loadPoSHModules($PoSHModule) {
67 | If(@(Get-Module | Where-Object {$_.Name -eq $PoSHModule}).count -eq 0) {
68 | If(@(Get-Module -ListAvailable | Where-Object {$_.Name -eq $PoSHModule} ).count -ne 0) {
69 | Import-Module $PoSHModule
70 | Write-Host ""
71 | Write-Host "PoSH Module '$PoSHModule' Has Been Loaded..." -ForeGroundColor Green
72 | Write-Host "Continuing Script..." -ForeGroundColor Green
73 | Write-Host ""
74 | } Else {
75 | Write-Host ""
76 | Write-Host "PoSH Module '$PoSHModule' Is Not Available To Load..." -ForeGroundColor Red
77 | Write-Host "Aborting Script..." -ForeGroundColor Red
78 | Write-Host ""
79 |
80 | EXIT
81 | }
82 | } Else {
83 | Write-Host ""
84 | Write-Host "PoSH Module '$PoSHModule' Already Loaded..." -ForeGroundColor Yellow
85 | Write-Host "Continuing Script..." -ForeGroundColor Yellow
86 | Write-Host ""
87 | }
88 | }
89 |
90 | ### FUNCTION: Test The Port Connection
91 | Function portConnectionCheck($fqdnServer, $port, $timeOut) {
92 | # Test To See If The HostName Is Resolvable At All
93 | Try {
94 | [System.Net.Dns]::gethostentry($fqdnServer) | Out-Null
95 | } Catch {
96 | Return "ERROR"
97 | }
98 |
99 | $tcpPortSocket = $null
100 | $portConnect = $null
101 | $tcpPortWait = $null
102 | $tcpPortSocket = New-Object System.Net.Sockets.TcpClient
103 | $portConnect = $tcpPortSocket.BeginConnect($fqdnServer, $port, $null, $null)
104 | $tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut, $false)
105 | If(!$tcpPortWait) {
106 | $tcpPortSocket.Close()
107 | Return "ERROR"
108 | } Else {
109 | #$error.Clear()
110 | $ErrorActionPreference = "SilentlyContinue"
111 | $tcpPortSocket.EndConnect($portConnect) | Out-Null
112 | If (!$?) {
113 | Return "ERROR"
114 | } Else {
115 | Return "SUCCESS"
116 | }
117 | $tcpPortSocket.Close()
118 | $ErrorActionPreference = "Continue"
119 | }
120 | }
121 |
122 | ### Clear The Screen
123 | Clear-Host
124 |
125 | ### Configure The Appropriate Screen And Buffer Size To Make Sure Everything Fits Nicely
126 | $uiConfig = (Get-Host).UI.RawUI
127 | $uiConfig.WindowTitle = "+++ SCAN AND CHECK ALL ACCOUNTS IN AD FOREST - BASIC INFO +++"
128 | $uiConfig.ForegroundColor = "Yellow"
129 | $uiConfigBufferSize = $uiConfig.BufferSize
130 | $uiConfigBufferSize.Width = 160
131 | $uiConfigBufferSize.Height = 9999
132 | $uiConfigScreenSizeMax = $uiConfig.MaxPhysicalWindowSize
133 | $uiConfigScreenSizeMaxWidth = $uiConfigScreenSizeMax.Width
134 | $uiConfigScreenSizeMaxHeight = $uiConfigScreenSizeMax.Height
135 | $uiConfigScreenSize = $uiConfig.WindowSize
136 | If ($uiConfigScreenSizeMaxWidth -lt 160) {
137 | $uiConfigScreenSize.Width = $uiConfigScreenSizeMaxWidth
138 | } Else {
139 | $uiConfigScreenSize.Width = 160
140 | }
141 | If ($uiConfigScreenSizeMaxHeight -lt 75) {
142 | $uiConfigScreenSize.Height = $uiConfigScreenSizeMaxHeight - 5
143 | } Else {
144 | $uiConfigScreenSize.Height = 75
145 | }
146 | $uiConfig.BufferSize = $uiConfigBufferSize
147 | $uiConfig.WindowSize = $uiConfigScreenSize
148 |
149 | ### Definition Of Some Constants
150 | $startExecDateTime = Get-Date
151 | $execStartDateTimeDisplay = Get-Date $startExecDateTime -Format "yyyy-MM-dd HH:mm:ss"
152 | $execStartDateTimeCustom = Get-Date $startExecDateTime -Format "yyyy-MM-dd_HH.mm.ss"
153 | $currentScriptFilePath = $MyInvocation.MyCommand.Definition
154 | $currentScriptFolderPath = Split-Path $currentScriptFilePath
155 | $thisADForest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
156 | $thisADForestRootDomain = $thisADForest.RootDomain.Name
157 | $outputCSVFileName = $($execStartDateTimeCustom + "_" + $thisADForestRootDomain + "_Scan-And-Check-All-Accounts-In-AD-Forest_01_Basic-Info.csv")
158 | $outputCSVFilePath = $currentScriptFolderPath + "\" + $outputCSVFileName
159 | $logFileName = $($execStartDateTimeCustom + "_" + $thisADForestRootDomain + "_Scan-And-Check-All-Accounts-In-AD-Forest_01_Basic-Info.log")
160 | $logFilePath = $currentScriptFolderPath + "\" + $logFileName
161 |
162 | Logging "" "HEADER"
163 | Logging " **********************************************************************************" "HEADER"
164 | Logging " * *" "HEADER"
165 | Logging " * --> Scan And Check All Accounts In AD Forest - Basic Info <-- *" "HEADER"
166 | Logging " * *" "HEADER"
167 | Logging " * Written By: Jorge de Almeida Pinto [MVP-EMS] *" "HEADER"
168 | Logging " * *" "HEADER"
169 | Logging " * BLOG: http://jorgequestforknowledge.wordpress.com/ *" "HEADER"
170 | Logging " * *" "HEADER"
171 | Logging " **********************************************************************************" "HEADER"
172 | Logging "" "HEADER"
173 |
174 | ### Test For Availability Of PowerShell CMDlets And Load Required PowerShell Module
175 | "ActiveDirectory" | %{loadPoSHModules $_}
176 |
177 | ### Define The Empty Table To Hold All The Gathered Data
178 | $accountData = @()
179 |
180 | ### Retrieve AD Forest Info
181 | $adforest = Get-ADForest
182 |
183 | # AD Forest FQDN
184 | $adForestRootDomainFQDN = $adforest.RootDomain
185 |
186 | # AD Forest Root Domain
187 | $adForestRootDomain = Get-ADDomain $adForestRootDomainFQDN
188 |
189 | # AD Forest DN
190 | $adForestRootDomainDN = $adForestRootDomain.DistinguishedName
191 |
192 | # AD Forest Domain SID
193 | $adForestRootDomainDomainSID = $adForestRootDomain.DomainSID.Value
194 |
195 | # Nearest AD DC For AD Forest Info
196 | $adRwdcFQDN = ((Get-ADDomainController -Discover).HostName)[0]
197 |
198 | # Nearest AD GC
199 | $adGcFQDN = (Get-ADDomainController -Discover -Service GlobalCatalog).HostName[0]
200 |
201 | # Root DSE Of The AD DC
202 | $adRootDSENearestRWDC = Get-ADRootDSE -Server $adRwdcFQDN
203 |
204 | # Schema NC DN
205 | $adForestSchemaNC = $adRootDSENearestRWDC.schemaNamingContext
206 |
207 | # Config NC DN
208 | $adForestConfigNC = $adRootDSENearestRWDC.configurationNamingContext
209 |
210 | ### Displaying The AD Forest Info
211 | Logging ""
212 | Logging "AD Forest...................: '$adForestRootDomainFQDN'"
213 | Logging "Nearest RWDC For AD Info....: '$adRwdcFQDN'"
214 | Logging "Nearest GC For AD Info......: '$adGcFQDN'"
215 | Logging "AD Forest Root Domain DN....: '$adForestRootDomainDN'"
216 | Logging "Schema NC DN................: '$adForestSchemaNC'"
217 | Logging "Config NC DN ...............: '$adForestConfigNC'"
218 | Logging ""
219 |
220 | ### Security Principals Of Interest That Can Authenticate
221 | # At Least 1 Must Be Specified!
222 | $securityPrincipalsThatCanAuthN = @()
223 | $securityPrincipalsThatCanAuthN += "user"
224 | $securityPrincipalsThatCanAuthN += "computer"
225 | $securityPrincipalsThatCanAuthN += "msDS-GroupManagedServiceAccount"
226 | $securityPrincipalsThatCanAuthN += "inetOrgPerson"
227 |
228 | ### LDAP Filter To Find Security Principal That AuthN
229 | $ldapFilterClause = $null
230 | $ldapFilterSecurityPrincipalsThatCanAuthN = $null
231 | $securityPrincipalsThatCanAuthN | %{
232 | $securityPrincipalThatCanAuthN = $null
233 | $securityPrincipalThatCanAuthN = $_
234 | $ldapFilterClause = $ldapFilterClause + "(objectClass=$securityPrincipalThatCanAuthN)"
235 | }
236 | $ldapFilterClauseCount = ([regex]::Matches($ldapFilterClause, "objectClass")).count
237 | If ($ldapFilterClauseCount -eq 1) {
238 | $ldapFilterSecurityPrincipalsThatCanAuthN = $ldapFilterClause
239 | } Else {
240 | $ldapFilterSecurityPrincipalsThatCanAuthN = "(|" + $ldapFilterClause + ")"
241 | }
242 |
243 | ### Retrieve AD Domain FQDNs In AD Forest And Build The Order As Such The Forest Root AD Domain Is At The Top Of The List. This Is Done To Have The Processing Of The Accounts In A Specific Order
244 | # Get All AD Domains In The AD Forest
245 | $adDomainFQDNs = $adforest.Domains
246 |
247 | # Define Empty List Of FQDNs In The AD Forest
248 | $script:adDomainFQDNList = @()
249 |
250 | # Add The Forest Root AD Domain To That List
251 | $script:adDomainFQDNList += $adForestRootDomainFQDN
252 |
253 | # Continue If There Is More Than 1 AD Domain In The AD Forest
254 | If ($adDomainFQDNs.Count -gt 1) {
255 | # For Every Child AD Domain Under The Forest Root AD Domain Add It In A Sorted Manner To That List
256 | $adDomainFQDNs | ?{$_ -ne $adForestRootDomainFQDN -And $_ -match $adForestRootDomainFQDN} | Sort-Object | %{
257 | $script:adDomainFQDNList += $_
258 | }
259 | # Retrieve All Cross References In The AD Forest To Determine If other Tree Roots Are Available Or Not
260 | $adDomainCrossRefs = Get-ADObject -LDAPFilter "(&(objectClass=crossRef)(systemFlags:1.2.840.113556.1.4.803:=2))" -SearchBase "CN=Partitions,$adForestConfigNC" -Properties *
261 | $adRootDomainCrossRefDN = ($adDomainCrossRefs | ?{$_.nCName -eq $adForestRootDomainDN}).DistinguishedName
262 |
263 | # For Every Cross Reference Found Process It
264 | If ($adDomainCrossRefs) {
265 | # For Every Cross Reference Not Being The One For The Forest Root AD Domain, But Rather A Tree Root AD Domain, Process it
266 | $adDomainCrossRefs | ?{$_.rootTrust -eq $adRootDomainCrossRefDN} | %{
267 | # Distinguished Name Of The Naming Context Of The Tree Root AD Domain
268 | $ncName = $null
269 | $ncName = $_.nCName
270 |
271 | # The FQDN Of The Tree Root AD Domain
272 | $adDomainFQDN = $null
273 | $adDomainFQDN = $ncName.Replace(",DC=",".").Replace("DC=","")
274 |
275 | # Add It To The List Of FQDNs
276 | $script:adDomainFQDNList += $adDomainFQDN
277 |
278 | # For Every Child AD Domain Of The Tree Root AD Domain Add It In A Sorted Manner To That List
279 | $adDomainFQDNs | ?{$_ -ne $adDomainFQDN -And $_ -match $adDomainFQDN} | Sort-Object | %{
280 | $script:adDomainFQDNList += $_
281 | }
282 | }
283 | }
284 | }
285 |
286 | ### For Every AD Domain In The AD Forest, Now Process The Accounts From That AD Domain
287 | $adDomainFQDNList | %{
288 | # Define The Counter
289 | $totalAccounts = 0
290 |
291 | # Define The Start Execution Date And Time For This AD Domain
292 | $startExecDateTimeThisADDomain = $null
293 | $startExecDateTimeThisADDomain = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
294 |
295 | # AD Domain FQDN
296 | $adDomainFQDN = $null
297 | $adDomainFQDN = $_
298 |
299 | # AD Domain Object
300 | $adDomain = $null
301 | $adDomain = Get-ADDomain $adDomainFQDN
302 |
303 | # AD Domain NetBIOS Name
304 | $adDomainNBT = $null
305 | $adDomainNBT = $adDomain.NetBIOSName
306 |
307 | # AD Domain DN
308 | $adDomainDN = $null
309 | $adDomainDN = $adDomain.DistinguishedName
310 |
311 | # An RWDC For The AD Domain
312 | $adDomainRwdcFQDN = $null
313 | $adDomainRwdcFQDN = ((Get-ADDomainController -Domain $adDomainFQDN -Discover).HostName)[0]
314 |
315 | # All RWDCs In The AD Domain
316 | $adDomainRWDCsFQDN = $null
317 | $adDomainRWDCsFQDN = $adDomain.ReplicaDirectoryServers
318 |
319 | # All RODCs In The AD Domain
320 | $adDomainRODCsFQDN = $null
321 | $adDomainRODCsFQDN = $adDomain.ReadOnlyReplicaDirectoryServers
322 |
323 | # All DCs (RWDCs And RODCs) In The AD Domain
324 | $adDomainDCsFQDN = @()
325 | $adDomainDCsFQDN = $adDomainRWDCsFQDN + $adDomainRODCsFQDN
326 |
327 | # Display The Start Of Processing Certain AD Domain
328 | Logging "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "HEADER"
329 | Logging "" "HEADER"
330 | Logging "Starting Processing Security Principals That Can Authenticate From AD Domain '$adDomainFQDN ($adDomainDN) ($adDomainRwdcFQDN)'..." "HEADER"
331 | Logging "" "HEADER"
332 |
333 | # Get Accounts And Properties From Within Targeted Naming Context
334 | Logging " > Getting Objects And Properties From '$adDomainRwdcFQDN' Within '$adDomainDN'..." "REMARK"
335 | Logging "" "REMARK"
336 | $allAuthSecurityPrincipals = $null
337 | $allAuthSecurityPrincipals = Get-ADObject -LDAPFilter $ldapFilterSecurityPrincipalsThatCanAuthN -Server $adDomainRwdcFQDN -SearchBase $adDomainDN -Properties *
338 |
339 | # Determine The Amount Of Objects
340 | $allAuthSecurityPrincipalsCount = $null
341 | $allAuthSecurityPrincipalsCount = $allAuthSecurityPrincipals.Count
342 |
343 | # Determine The Length Of The Upper Value To Pad The Numbers So All Have The Same Width In The Output
344 | $lengthOfUpperValueTotalAccounts = $null
345 | $lengthOfUpperValueTotalAccounts = $allAuthSecurityPrincipalsCount.ToString().Length
346 | Logging " # Total Objects Found......: $allAuthSecurityPrincipalsCount" "REMARK"
347 | Logging "" "REMARK"
348 |
349 | # For Every Account In The List
350 | Logging " > Processing All Objects..." "REMARK"
351 | Logging "" "REMARK"
352 | If ($allAuthSecurityPrincipals) {
353 | $allAuthSecurityPrincipals | %{
354 | #Increase The Counter
355 | $totalAccounts++
356 |
357 | # The AD Object
358 | $authSecurityPrincipal = $null
359 | $authSecurityPrincipal = $_
360 |
361 | # The sAMAccountName Of The Object
362 | $sAMAccountName = $null
363 | $sAMAccountName = $authSecurityPrincipal.SamAccountName
364 |
365 | # The Account Name Of The Object
366 | $accountName = $null
367 | $accountName = $adDomainNBT + "\" + $sAMAccountName
368 |
369 | # Trust Objects Are Using The User Object Class. However, To Make It Clear It Is A Trust Object Determine If As Such A Define It Accordingly
370 | # Otherwise Define The Object Class As Listed
371 | If ($sAMAccountName.EndsWith('$') -And $($authSecurityPrincipal.objectClass) -eq "user") {
372 | $accountType = "trust (user)"
373 | } Else {
374 | $accountType = $authSecurityPrincipal.objectClass
375 | }
376 |
377 | # Get The UserPrincipalName
378 | $userPrincipalName = $null
379 | If ($authSecurityPrincipal.UserPrincipalName) {
380 | $userPrincipalName = $authSecurityPrincipal.UserPrincipalName
381 | } Else {
382 | $userPrincipalName = "NOT CONFIGURED"
383 | }
384 |
385 | # Get The ObjectGuid
386 | $objectGuid = $null
387 | $objectGuid = $authSecurityPrincipal.ObjectGUID.Guid
388 |
389 | # Get The Display Name
390 | $displayName = $null
391 | If ($authSecurityPrincipal.DisplayName) {
392 | $displayName = $authSecurityPrincipal.DisplayName
393 | } Else {
394 | $displayName = "NOT CONFIGURED"
395 | }
396 |
397 | # Get The Account Enabled Or Disabled
398 | # UserAccountControl: ACCOUNTDISABLE (2, 0x0002)
399 | $accountIsEnabled = $null
400 | If ($($authSecurityPrincipal.userAccountControl -band 2) -eq 0) {
401 | $accountIsEnabled = $true
402 | } Else {
403 | $accountIsEnabled = $false
404 | }
405 |
406 | # Check If The Account Is Locked Or Unlocked
407 | $accountIsLocked = $null
408 | $accountLockoutFileTime = $null
409 | $accountLockoutFileTime = $authSecurityPrincipal.lockoutTime
410 | $accountLockoutDateTime = $null
411 | If ($accountLockoutFileTime -eq $null -Or $accountLockoutFileTime -eq "") {
412 | $accountIsLocked = "FALSE - Never Locked"
413 | } ElseIf ($accountLockoutFileTime -eq 0) {
414 | $accountIsLocked = "FALSE - Has Been Locked Before"
415 | } Else {
416 | $accountLockoutDateTime = Get-Date $([datetime]::fromFileTime($accountLockoutFileTime)) -Format "yyyy-MM-dd HH:mm:ss"
417 | $accountIsLocked = "TRUE - At: $accountLockoutDateTime"
418 | }
419 |
420 | # Get The Account Expiration Date/Time And Convert It From Filetime To Normal Date/Time
421 | $accountExpirationFileTime = $null
422 | $accountExpirationFileTime = $authSecurityPrincipal.accountExpires
423 | $accountExpirationDateTime = $null
424 | If ($accountExpirationFileTime -eq 0 -Or $accountExpirationFileTime -eq 9223372036854775807) {
425 | $accountExpirationDateTime = "NEVER"
426 | } Else {
427 | $accountExpirationDateTime = Get-Date $([datetime]::fromFileTime($accountExpirationFileTime)) -Format "yyyy-MM-dd HH:mm:ss"
428 | }
429 |
430 | # Get The Password Last Set Date/Time And Convert It From Filetime To Normal Date/Time
431 | $pwdLastSetFileTime = $null
432 | $pwdLastSetFileTime = $authSecurityPrincipal.pwdLastSet
433 | $pwdLastSetDateTime = $null
434 | If ($pwdLastSetFileTime -eq 0) {
435 | $pwdLastSetDateTime = "Must Chng At Next Logon"
436 | } Else {
437 | $pwdLastSetDateTime = Get-Date $([datetime]::fromFileTime($pwdLastSetFileTime)) -Format "yyyy-MM-dd HH:mm:ss"
438 | }
439 |
440 | # Check If The Account Has Password Never Expires
441 | # UserAccountControl: DONT_EXPIRE_PASSWD (65536, 0x10000) | Misc User Account Control Values https://support.microsoft.com/en-gb/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
442 | $accountPwdNeverExpires = $null
443 | If ($($authSecurityPrincipal.userAccountControl -band 65536) -eq 65536) {
444 | $accountPwdNeverExpires = $true
445 | } Else {
446 | $accountPwdNeverExpires = $false
447 | }
448 |
449 | # Get The Account Last Logon TimeStamp Date/Time And Convert It From Filetime To Normal Date/Time (Does Replicate)
450 | $accountLastLogonTimeStampFileTime = $null
451 | $accountLastLogonTimeStampFileTime = $authSecurityPrincipal.lastLogonTimestamp
452 | $accountLastLogonTimeStampDateTime = $null
453 | If ($accountLastLogonTimeStampFileTime) {
454 | $accountLastLogonTimeStampDateTime = Get-Date $([datetime]::fromFileTime($accountLastLogonTimeStampFileTime)) -Format "yyyy-MM-dd HH:mm:ss"
455 | } Else {
456 | $accountLastLogonTimeStampDateTime = "NEVER"
457 | }
458 |
459 | # Get The Account Last Logon Date/Time And Convert It From Filetime To Normal Date/Time (Specific Per RWDC And DOES NOT Replicate)
460 | $accountLastLogonDateTimeOnDCs = @()
461 | $adDomainDCsFQDN | %{
462 | $adDomainDCFQDN = $null
463 | $adDomainDCFQDN = $_
464 | $lastLogonOnDCFileTime = $null
465 | $lastLogonOnDCDateTime = $null
466 |
467 | # Check The Connection To The RWDC
468 | $ports = 389 # LDAP
469 | $connectionCheckOK = $true
470 | $ports | %{
471 | $port = $null
472 | $port = $_
473 | $connectionResult = $null
474 | $connectionResult = portConnectionCheck $adDomainDCFQDN $port 100
475 | If ($connectionResult -eq "ERROR") {
476 | $connectionCheckOK = $false
477 | }
478 | }
479 | If ($connectionCheckOK -eq $true) {
480 | Try {
481 | $lastLogonOnDCFileTime = (Get-ADObject -Identity $objectGuid -Server $adDomainDCFQDN -Properties lastLogon).lastLogon
482 | } Catch {
483 | $lastLogonOnDCFileTime = "FAILED/NOT AVAILABLE"
484 | }
485 | If ($lastLogonOnDCFileTime -eq "FAILED/NOT AVAILABLE") {
486 | $lastLogonOnDCDateTime = "FAILED/NOT AVAILABLE (on '$adDomainDCFQDN')"
487 | } ElseIf ($lastLogonOnDCFileTime -eq $null -Or $lastLogonOnDCFileTime -eq "" -Or $lastLogonOnDCFileTime -eq 0) {
488 | $lastLogonOnDCDateTime = "NEVER (on '$adDomainDCFQDN')"
489 | } Else {
490 | $lastLogonOnDCDateTime = "$(Get-Date $([datetime]::fromFileTime($lastLogonOnDCFileTime)) -Format 'yyyy-MM-dd HH:mm:ss') (On '$adDomainDCFQDN')"
491 | }
492 | } Else {
493 | $lastLogonOnDCDateTime = "FAILED/NOT AVAILABLE (on '$adDomainDCFQDN')"
494 | }
495 | $accountLastLogonDateTimeOnDCs += $lastLogonOnDCDateTime
496 | }
497 | $accountLastLogonDateTimeOnDCs = $accountLastLogonDateTimeOnDCs -join ",`n"
498 |
499 | # Display Some Info On Screen So That It Is Visible Something Is Happening
500 | Logging " # $($totalAccounts.ToString().PadLeft($lengthOfUpperValueTotalAccounts, '0')) Of $allAuthSecurityPrincipalsCount - Processing Account '$adDomainFQDN\$sAMAccountName' ($accountType)..." "REMARK"
501 | Logging "" "REMARK"
502 |
503 | # Create An Object Entry For The Account And Add It To The Total List
504 | $accountEntry = New-Object -TypeName System.Object
505 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain FQDN" -Value $adDomainFQDN
506 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain NBT" -Value $adDomainNBT
507 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain DN" -Value $adDomainDN
508 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Sam Account Name" -Value $sAMAccountName
509 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Account Name" -Value $accountName
510 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Account Type" -Value $accountType
511 | $accountEntry | Add-Member -MemberType NoteProperty -Name "User Principal Name" -Value $userPrincipalName
512 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Display Name" -Value $displayName
513 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Enabled" -Value $accountIsEnabled
514 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Locked" -Value $accountIsLocked
515 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Account Expires On" -Value $accountExpirationDateTime
516 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Pwd Last Set On" -Value $pwdLastSetDateTime
517 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Pwd Never Expires" -Value $accountPwdNeverExpires
518 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Last Logon Timestamp" -Value $accountLastLogonTimeStampDateTime
519 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Last Logon (Per RWDC)" -Value $accountLastLogonDateTimeOnDCs
520 | $accountData += $accountEntry
521 | }
522 | } Else {
523 | Logging "" "REMARK"
524 | Logging " > What The Heck? No Objects? Looks Like It!..." "REMARK"
525 | Logging "" "REMARK"
526 | }
527 |
528 | # Define The End Execution Date And Time For This AD Domain
529 | $endExecDateTimeThisADDomain = $null
530 | $endExecDateTimeThisADDomain = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
531 |
532 | # Calculate The Time Spent For This AD Domain
533 | $timeDiff = $null
534 | $timeDiff = (New-Timespan -Start $(Get-Date $startExecDateTimeThisADDomain) -End $(Get-Date $endExecDateTimeThisADDomain)).TotalMinutes
535 |
536 | Logging "" "REMARK"
537 | Logging " > Finished Processing AD Domain '$adDomainFQDN'..." "REMARK"
538 | Logging " > Start Time...........: $startExecDateTimeThisADDomain" "REMARK"
539 | Logging " > End Time.............: $endExecDateTimeThisADDomain" "REMARK"
540 | Logging " > Duration (Minutes)...: $timeDiff" "REMARK"
541 | Logging "" "REMARK"
542 | }
543 |
544 | # Define The End Execution Date And Time
545 | $execEndDateTimeDisplay = Get-Date -Format "yyyy-MM-dd_HH.mm.ss"
546 | Logging "End Date/Time Script................................: $execEndDateTimeDisplay"
547 | Logging ""
548 |
549 | # Define The Location Of The Report
550 | Logging "CSV Report AD Account Scan (Folder).................: $currentScriptFolderPath"
551 | Logging "CSV Report AD Account Scan (File Name)..............: $outputCSVFileName"
552 | Logging ""
553 |
554 | # Define The Location Of The Log File
555 | Logging "Log File AD Account Scan (Folder)...................: $currentScriptFolderPath"
556 | Logging "Log File AD Account Scan (File Name)................: $logFileName"
557 | Logging ""
558 |
559 | # Sort The Table/List
560 | #$accountDataSorted = $accountData | Sort-Object -Descending:$False -Property "Domain NBT","Account Type","Account Name"
561 |
562 | # Export The Table/List To The CSV File
563 | #$accountDataSorted | Export-Csv -Path $outputCSVFilePath -Force -NoTypeInformation
564 | #$accountDataSorted | Out-GridView
565 | $accountData | Export-Csv -Path $outputCSVFilePath -Force -NoTypeInformation
566 | $accountData | Out-GridView
567 | Write-Host ""
568 | Write-Host "DONE!"
569 | Write-Host ""
--------------------------------------------------------------------------------
/Scan-And-Check-All-Accounts-In-AD-Forest_02_Delegation-Info.ps1:
--------------------------------------------------------------------------------
1 | ### Abstract: This PoSH Script Scans And Checks All Accounts In The AD Forest And Creates A CSV Report And Outputs To GridView
2 | ### Written by: Jorge de Almeida Pinto [MVP-EMS]
3 | ### BLOG: http://jorgequestforknowledge.wordpress.com/
4 | ###
5 | ### 2019-10-26: Initial version of the script (v0.1)
6 | ###
7 |
8 | <#
9 | .SYNOPSIS
10 | .DESCRIPTION
11 | This PoSH Script Leverages LDAP Queries To:
12 | * Generate CSV Report With The Results. For every account (user, computer, gMSA, inetOrgPerson), the following is gathered and listed
13 | * Domain FQDN (e.g. 'IAMTEC.NET')
14 | * Domain NBT (e.g. 'IAMTEC')
15 | * Domain DN (e.g. 'DC=IAMTEC,DC=NET')
16 | * Sam Account Name (e.g. 'jorge')
17 | * Account Name (e.g. 'IAMTEC\jorge')
18 | * Account Type (computer, inetOrgPerson, msDS-GroupManagedServiceAccount, trust (user), user)
19 | * Service Principal Name(s) (e.g. or "No SPNs")
20 | * Acc Based Deleg Type (e.g. "No-Acc-Deleg" or "Acc-Unc-Deleg" or "Acc-Con-Deleg-AnyAuthN" or "Acc-Con-Deleg-KerbAuthN"
21 | * Acc Based Deleg To (e.g. or "No Delegated SPNs")
22 | * Res Based Deleg For (e.g. or "No-Res-Deleg")
23 |
24 | .EXAMPLE
25 | Scan/Check All Accounts In The AD Forest And Create The Report
26 |
27 | .\Scan-And-Check-All-Accounts-In-AD-Forest_02_Delegation-Info.ps1
28 |
29 | .NOTES
30 | This script requires:
31 | * PowerShell Module: ActiveDirectory
32 | * Basic Permissions, Nothing Special!
33 | #>
34 |
35 | ### FUNCTION: Logging Data To The Log File
36 | Function Logging($dataToLog, $lineType) {
37 | $datetimeLogLine = "[" + $(Get-Date -format "yyyy-MM-dd HH:mm:ss") + "] : "
38 | Out-File -filepath "$logFilePath" -append -inputObject "$datetimeLogLine$dataToLog"
39 | #Write-Output($datetimeLogLine + $dataToLog)
40 | If ($lineType -eq $NULL) {
41 | Write-Host "$datetimeLogLine$dataToLog"
42 | }
43 | If ($lineType -eq "SUCCESS") {
44 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Green
45 | }
46 | If ($lineType -eq "ERROR") {
47 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
48 | }
49 | If ($lineType -eq "WARNING") {
50 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Red
51 | }
52 | If ($lineType -eq "HEADER") {
53 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Magenta
54 | }
55 | If ($lineType -eq "REMARK") {
56 | Write-Host "$datetimeLogLine$dataToLog" -ForeGroundColor Cyan
57 | }
58 | }
59 |
60 | ### FUNCTION: Load Required PowerShell Modules
61 | Function loadPoSHModules($PoSHModule) {
62 | If(@(Get-Module | Where-Object {$_.Name -eq $PoSHModule}).count -eq 0) {
63 | If(@(Get-Module -ListAvailable | Where-Object {$_.Name -eq $PoSHModule} ).count -ne 0) {
64 | Import-Module $PoSHModule
65 | Write-Host ""
66 | Write-Host "PoSH Module '$PoSHModule' Has Been Loaded..." -ForeGroundColor Green
67 | Write-Host "Continuing Script..." -ForeGroundColor Green
68 | Write-Host ""
69 | } Else {
70 | Write-Host ""
71 | Write-Host "PoSH Module '$PoSHModule' Is Not Available To Load..." -ForeGroundColor Red
72 | Write-Host "Aborting Script..." -ForeGroundColor Red
73 | Write-Host ""
74 |
75 | EXIT
76 | }
77 | } Else {
78 | Write-Host ""
79 | Write-Host "PoSH Module '$PoSHModule' Already Loaded..." -ForeGroundColor Yellow
80 | Write-Host "Continuing Script..." -ForeGroundColor Yellow
81 | Write-Host ""
82 | }
83 | }
84 |
85 | <#
86 | ### FUNCTION: Test The Port Connection
87 | Function portConnectionCheck($fqdnServer, $port, $timeOut) {
88 | # Test To See If The HostName Is Resolvable At All
89 | Try {
90 | [System.Net.Dns]::gethostentry($fqdnServer) | Out-Null
91 | } Catch {
92 | Return "ERROR"
93 | }
94 |
95 | $tcpPortSocket = $null
96 | $portConnect = $null
97 | $tcpPortWait = $null
98 | $tcpPortSocket = New-Object System.Net.Sockets.TcpClient
99 | $portConnect = $tcpPortSocket.BeginConnect($fqdnServer, $port, $null, $null)
100 | $tcpPortWait = $portConnect.AsyncWaitHandle.WaitOne($timeOut, $false)
101 | If(!$tcpPortWait) {
102 | $tcpPortSocket.Close()
103 | Return "ERROR"
104 | } Else {
105 | #$error.Clear()
106 | $ErrorActionPreference = "SilentlyContinue"
107 | $tcpPortSocket.EndConnect($portConnect) | Out-Null
108 | If (!$?) {
109 | Return "ERROR"
110 | } Else {
111 | Return "SUCCESS"
112 | }
113 | $tcpPortSocket.Close()
114 | $ErrorActionPreference = "Continue"
115 | }
116 | }
117 | #>
118 |
119 | ### Clear The Screen
120 | Clear-Host
121 |
122 | ### Configure The Appropriate Screen And Buffer Size To Make Sure Everything Fits Nicely
123 | $uiConfig = (Get-Host).UI.RawUI
124 | $uiConfig.WindowTitle = "+++ SCAN AND CHECK ALL ACCOUNTS IN AD FOREST - DELEGATION INFO +++"
125 | $uiConfig.ForegroundColor = "Yellow"
126 | $uiConfigBufferSize = $uiConfig.BufferSize
127 | $uiConfigBufferSize.Width = 160
128 | $uiConfigBufferSize.Height = 9999
129 | $uiConfigScreenSizeMax = $uiConfig.MaxPhysicalWindowSize
130 | $uiConfigScreenSizeMaxWidth = $uiConfigScreenSizeMax.Width
131 | $uiConfigScreenSizeMaxHeight = $uiConfigScreenSizeMax.Height
132 | $uiConfigScreenSize = $uiConfig.WindowSize
133 | If ($uiConfigScreenSizeMaxWidth -lt 160) {
134 | $uiConfigScreenSize.Width = $uiConfigScreenSizeMaxWidth
135 | } Else {
136 | $uiConfigScreenSize.Width = 160
137 | }
138 | If ($uiConfigScreenSizeMaxHeight -lt 75) {
139 | $uiConfigScreenSize.Height = $uiConfigScreenSizeMaxHeight - 5
140 | } Else {
141 | $uiConfigScreenSize.Height = 75
142 | }
143 | $uiConfig.BufferSize = $uiConfigBufferSize
144 | $uiConfig.WindowSize = $uiConfigScreenSize
145 |
146 | ### Definition Of Some Constants
147 | $startExecDateTime = Get-Date
148 | $execStartDateTimeDisplay = Get-Date $startExecDateTime -Format "yyyy-MM-dd HH:mm:ss"
149 | $execStartDateTimeCustom = Get-Date $startExecDateTime -Format "yyyy-MM-dd_HH.mm.ss"
150 | $currentScriptFilePath = $MyInvocation.MyCommand.Definition
151 | $currentScriptFolderPath = Split-Path $currentScriptFilePath
152 | $thisADForest = [DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
153 | $thisADForestRootDomain = $thisADForest.RootDomain.Name
154 | $outputCSVFileName = $($execStartDateTimeCustom + "_" + $thisADForestRootDomain + "_Scan-And-Check-All-Accounts-In-AD-Forest_02_Delegation-Info.csv")
155 | $outputCSVFilePath = $currentScriptFolderPath + "\" + $outputCSVFileName
156 | $logFileName = $($execStartDateTimeCustom + "_" + $thisADForestRootDomain + "_Scan-And-Check-All-Accounts-In-AD-Forest_02_Delegation-Info.log")
157 | $logFilePath = $currentScriptFolderPath + "\" + $logFileName
158 |
159 | Logging "" "HEADER"
160 | Logging " **********************************************************************************" "HEADER"
161 | Logging " * *" "HEADER"
162 | Logging " * --> Scan And Check All Accounts In AD Forest - Delegation Info <-- *" "HEADER"
163 | Logging " * *" "HEADER"
164 | Logging " * Written By: Jorge de Almeida Pinto [MVP-EMS] *" "HEADER"
165 | Logging " * *" "HEADER"
166 | Logging " * BLOG: http://jorgequestforknowledge.wordpress.com/ *" "HEADER"
167 | Logging " * *" "HEADER"
168 | Logging " **********************************************************************************" "HEADER"
169 | Logging "" "HEADER"
170 |
171 | ### Test For Availability Of PowerShell CMDlets And Load Required PowerShell Module
172 | "ActiveDirectory" | %{loadPoSHModules $_}
173 |
174 | ### Define The Empty Table To Hold All The Gathered Data
175 | $accountData = @()
176 |
177 | ### Retrieve AD Forest Info
178 | $adforest = Get-ADForest
179 |
180 | # AD Forest FQDN
181 | $adForestRootDomainFQDN = $adforest.RootDomain
182 |
183 | # AD Forest Root Domain
184 | $adForestRootDomain = Get-ADDomain $adForestRootDomainFQDN
185 |
186 | # AD Forest DN
187 | $adForestRootDomainDN = $adForestRootDomain.DistinguishedName
188 |
189 | # AD Forest Domain SID
190 | $adForestRootDomainDomainSID = $adForestRootDomain.DomainSID.Value
191 |
192 | # Nearest AD DC For AD Forest Info
193 | $adRwdcFQDN = ((Get-ADDomainController -Discover).HostName)[0]
194 |
195 | # Nearest AD GC
196 | $adGcFQDN = (Get-ADDomainController -Discover -Service GlobalCatalog).HostName[0]
197 |
198 | # Root DSE Of The AD DC
199 | $adRootDSENearestRWDC = Get-ADRootDSE -Server $adRwdcFQDN
200 |
201 | # Schema NC DN
202 | $adForestSchemaNC = $adRootDSENearestRWDC.schemaNamingContext
203 |
204 | # Config NC DN
205 | $adForestConfigNC = $adRootDSENearestRWDC.configurationNamingContext
206 |
207 | ### Displaying The AD Forest Info
208 | Logging ""
209 | Logging "AD Forest...................: '$adForestRootDomainFQDN'"
210 | Logging "Nearest RWDC For AD Info....: '$adRwdcFQDN'"
211 | Logging "Nearest GC For AD Info......: '$adGcFQDN'"
212 | Logging "AD Forest Root Domain DN....: '$adForestRootDomainDN'"
213 | Logging "Schema NC DN................: '$adForestSchemaNC'"
214 | Logging "Config NC DN ...............: '$adForestConfigNC'"
215 | Logging ""
216 |
217 | ### Security Principals Of Interest That Can Authenticate
218 | # At Least 1 Must Be Specified!
219 | $securityPrincipalsThatCanAuthN = @()
220 | $securityPrincipalsThatCanAuthN += "user"
221 | $securityPrincipalsThatCanAuthN += "computer"
222 | $securityPrincipalsThatCanAuthN += "msDS-GroupManagedServiceAccount"
223 | $securityPrincipalsThatCanAuthN += "inetOrgPerson"
224 |
225 | ### LDAP Filter To Find Security Principal That AuthN
226 | $ldapFilterClause = $null
227 | $ldapFilterSecurityPrincipalsThatCanAuthN = $null
228 | $securityPrincipalsThatCanAuthN | %{
229 | $securityPrincipalThatCanAuthN = $null
230 | $securityPrincipalThatCanAuthN = $_
231 | $ldapFilterClause = $ldapFilterClause + "(objectClass=$securityPrincipalThatCanAuthN)"
232 | }
233 | $ldapFilterClauseCount = ([regex]::Matches($ldapFilterClause, "objectClass")).count
234 | If ($ldapFilterClauseCount -eq 1) {
235 | $ldapFilterSecurityPrincipalsThatCanAuthN = $ldapFilterClause
236 | } Else {
237 | $ldapFilterSecurityPrincipalsThatCanAuthN = "(|" + $ldapFilterClause + ")"
238 | }
239 |
240 | ### Retrieve AD Domain FQDNs In AD Forest And Build The Order As Such The Forest Root AD Domain Is At The Top Of The List. This Is Done To Have The Processing Of The Accounts In A Specific Order
241 | # Get All AD Domains In The AD Forest
242 | $adDomainFQDNs = $adforest.Domains
243 |
244 | # Define Empty List Of FQDNs In The AD Forest
245 | $script:adDomainFQDNList = @()
246 |
247 | # Add The Forest Root AD Domain To That List
248 | $script:adDomainFQDNList += $adForestRootDomainFQDN
249 |
250 | # Continue If There Is More Than 1 AD Domain In The AD Forest
251 | If ($adDomainFQDNs.Count -gt 1) {
252 | # For Every Child AD Domain Under The Forest Root AD Domain Add It In A Sorted Manner To That List
253 | $adDomainFQDNs | ?{$_ -ne $adForestRootDomainFQDN -And $_ -match $adForestRootDomainFQDN} | Sort-Object | %{
254 | $script:adDomainFQDNList += $_
255 | }
256 |
257 | # Retrieve All Cross References In The AD Forest To Determine If other Tree Roots Are Available Or Not
258 | $adDomainCrossRefs = Get-ADObject -LDAPFilter "(&(objectClass=crossRef)(systemFlags:1.2.840.113556.1.4.803:=2))" -SearchBase "CN=Partitions,$adForestConfigNC" -Properties *
259 | $adRootDomainCrossRefDN = ($adDomainCrossRefs | ?{$_.nCName -eq $adForestRootDomainDN}).DistinguishedName
260 |
261 | # For Every Cross Reference Found Process It
262 | If ($adDomainCrossRefs) {
263 | # For Every Cross Reference Not Being The One For The Forest Root AD Domain, But Rather A Tree Root AD Domain, Process it
264 | $adDomainCrossRefs | ?{$_.rootTrust -eq $adRootDomainCrossRefDN} | %{
265 | # Distinguished Name Of The Naming Context Of The Tree Root AD Domain
266 | $ncName = $null
267 | $ncName = $_.nCName
268 |
269 | # The FQDN Of The Tree Root AD Domain
270 | $adDomainFQDN = $null
271 | $adDomainFQDN = $ncName.Replace(",DC=",".").Replace("DC=","")
272 |
273 | # Add It To The List Of FQDNs
274 | $script:adDomainFQDNList += $adDomainFQDN
275 |
276 | # For Every Child AD Domain Of The Tree Root AD Domain Add It In A Sorted Manner To That List
277 | $adDomainFQDNs | ?{$_ -ne $adDomainFQDN -And $_ -match $adDomainFQDN} | Sort-Object | %{
278 | $script:adDomainFQDNList += $_
279 | }
280 | }
281 | }
282 | }
283 |
284 | ### For Every AD Domain In The AD Forest, Now Process The Accounts From That AD Domain
285 | $adDomainFQDNList | %{
286 | # Define The Counter
287 | $totalAccounts = 0
288 |
289 | # Define The Start Execution Date And Time For This AD Domain
290 | $startExecDateTimeThisADDomain = $null
291 | $startExecDateTimeThisADDomain = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
292 |
293 | # AD Domain FQDN
294 | $adDomainFQDN = $null
295 | $adDomainFQDN = $_
296 |
297 | # AD Domain Object
298 | $adDomain = $null
299 | $adDomain = Get-ADDomain $adDomainFQDN
300 |
301 | # AD Domain NetBIOS Name
302 | $adDomainNBT = $null
303 | $adDomainNBT = $adDomain.NetBIOSName
304 |
305 | # AD Domain DN
306 | $adDomainDN = $null
307 | $adDomainDN = $adDomain.DistinguishedName
308 |
309 | # An RWDC For The AD Domain
310 | $adDomainRwdcFQDN = $null
311 | $adDomainRwdcFQDN = ((Get-ADDomainController -Domain $adDomainFQDN -Discover).HostName)[0]
312 |
313 | # Display The Start Of Processing Certain AD Domain
314 | Logging "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" "HEADER"
315 | Logging "" "HEADER"
316 | Logging "Starting Processing Security Principals That Can Authenticate From AD Domain '$adDomainFQDN ($adDomainDN) ($adDomainRwdcFQDN)'..." "HEADER"
317 | Logging "" "HEADER"
318 |
319 | # Get Accounts And Properties From Within Targeted Naming Context
320 | Logging " > Getting Objects And Properties From '$adDomainRwdcFQDN' Within '$adDomainDN'..." "REMARK"
321 | Logging "" "REMARK"
322 | $allAuthSecurityPrincipals = $null
323 | $allAuthSecurityPrincipals = Get-ADObject -LDAPFilter $ldapFilterSecurityPrincipalsThatCanAuthN -Server $adDomainRwdcFQDN -SearchBase $adDomainDN -Properties *
324 |
325 | # Determine The Amount Of Objects
326 | $allAuthSecurityPrincipalsCount = $null
327 | $allAuthSecurityPrincipalsCount = $allAuthSecurityPrincipals.Count
328 |
329 | # Determine The Length Of The Upper Value To Pad The Numbers So All Have The Same Width In The Output
330 | $lengthOfUpperValueTotalAccounts = $null
331 | $lengthOfUpperValueTotalAccounts = $allAuthSecurityPrincipalsCount.ToString().Length
332 | Logging " # Total Objects Found......: $allAuthSecurityPrincipalsCount" "REMARK"
333 | Logging "" "REMARK"
334 |
335 | # For Every Account In The List
336 | Logging " > Processing All Objects..." "REMARK"
337 | Logging "" "REMARK"
338 | If ($allAuthSecurityPrincipals) {
339 | $allAuthSecurityPrincipals | %{
340 | #Increase The Counter
341 | $totalAccounts++
342 |
343 | # The AD Object
344 | $authSecurityPrincipal = $null
345 | $authSecurityPrincipal = $_
346 |
347 | # The sAMAccountName Of The Object
348 | $sAMAccountName = $null
349 | $sAMAccountName = $authSecurityPrincipal.SamAccountName
350 |
351 | # The Account Name Of The Object
352 | $accountName = $null
353 | $accountName = $adDomainNBT + "\" + $sAMAccountName
354 |
355 | # Trust Objects Are Using The User Object Class. However, To Make It Clear It Is A Trust Object Determine If As Such A Define It Accordingly
356 | # Otherwise Define The Object Class As Listed
357 | If ($sAMAccountName.EndsWith('$') -And $($authSecurityPrincipal.objectClass) -eq "user") {
358 | $accountType = "trust (user)"
359 | } Else {
360 | $accountType = $authSecurityPrincipal.objectClass
361 | }
362 |
363 | # Check If The Account Has Based Kerberos Delegation Configured
364 | # TRUSTED_FOR_DELEGATION (524288, 0x80000) | Misc User Account Control Values https://support.microsoft.com/en-gb/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
365 | $accountIsTrustedForUnConstrainedDeleg = $null
366 | If ($($authSecurityPrincipal.userAccountControl -band 524288) -eq 524288) {
367 | $accountIsTrustedForUnConstrainedDeleg = $true
368 | } Else {
369 | $accountIsTrustedForUnConstrainedDeleg = $false
370 | }
371 |
372 | # Determine If Account Based Kerberos Delegation
373 | # TRUSTED_TO_AUTH_FOR_DELEGATION (16777216, 0x1000000) | Misc User Account Control Values https://support.microsoft.com/en-gb/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
374 | $accountIsTrustedForConstrainedDelegAnyAuthN = $null
375 | If ($($authSecurityPrincipal.userAccountControl -band 16777216) -eq 16777216) {
376 | $accountIsTrustedForConstrainedDelegAnyAuthN = $true
377 | } Else {
378 | $accountIsTrustedForConstrainedDelegAnyAuthN = $false
379 | }
380 |
381 | # Determine Account Delegation Type
382 | $accountBasedDelegType = $null
383 | If ($accountIsTrustedForUnConstrainedDeleg -eq $true) {
384 | # Account Based Unconstrained Delegation
385 | $accountBasedDelegType = "Acc-Unc-Deleg"
386 | } ElseIf ($accountIsTrustedForConstrainedDelegAnyAuthN -eq $true) {
387 | # Account Based Constrained Delegation - Any AuthN
388 | $accountBasedDelegType = "Acc-Con-Deleg-AnyAuthN"
389 | } ElseIf ($accountIsTrustedForUnConstrainedDeleg -eq $false -And $accountIsTrustedForConstrainedDelegAnyAuthN -eq $false -And $authSecurityPrincipal."msDS-AllowedToDelegateTo" -ne $null) {
390 | # Account Based Constrained Delegation - Kerberos AuthN
391 | $accountBasedDelegType = "Acc-Con-Deleg-KerbAuthN"
392 | } Else {
393 | # No Account Based Constrained Delegation
394 | $accountBasedDelegType = "No-Acc-Deleg"
395 | }
396 |
397 | # Check If The Account Has SPNs Configured Or Not
398 | $spnList = $null
399 | $spnList = $authSecurityPrincipal.servicePrincipalName
400 | If ($spnList) {
401 | $spnList = $spnList -join ",`n"
402 | } Else {
403 | $spnList = "No SPNs"
404 | }
405 |
406 | # Check If The Account Has Constrained Delegation Configured For Services Or Not, And If Yes Which Services
407 | $accountBasedConstrainedDelegationToList = $null
408 | If ($authSecurityPrincipal."msDS-AllowedToDelegateTo") {
409 | $accountBasedConstrainedDelegationToList = $authSecurityPrincipal."msDS-AllowedToDelegateTo"
410 | $accountBasedConstrainedDelegationToList = $accountBasedConstrainedDelegationToList -join ",`n"
411 | } ElseIf ($accountIsTrustedForUnConstrainedDeleg -eq $true) {
412 | $accountBasedConstrainedDelegationToList = "Any Applicable SPN (!)"
413 | } Else {
414 | $accountBasedConstrainedDelegationToList = "No Delegated SPNs"
415 | }
416 |
417 | # Check If The Account Has Resource Based Delegation Configured Or Not, And If Yes, From Which Accounts
418 | $accountHasResourceBasedDelegationConfigured = $null
419 | $accountHasResourceBasedDelegationConfigured = $authSecurityPrincipal."msDS-AllowedToActOnBehalfOfOtherIdentity"
420 | If ($accountHasResourceBasedDelegationConfigured) {
421 | # Get The Accounts Having Resource Based Delegation On This Account
422 | $accountsDelegatedForThisResource = $null
423 | $accountsDelegatedForThisResource = $authSecurityPrincipal."msDS-AllowedToActOnBehalfOfOtherIdentity".Access.IdentityReference.Value
424 |
425 | # The List Of Accounts Having Resource Based Delegation On This Account, With Additional Information
426 | $accountsDelegatedForThisResourceList = @()
427 |
428 | # For Every Account Having Resource Based Delegation On This Account
429 | $accountsDelegatedForThisResource | %{
430 | # Account Having Resource Based Delegation On This Account
431 | $accountDelegatedForThisResource = $null
432 | $accountDelegatedForThisResource = $_
433 |
434 | # Get The NetBIOS Name Of The AD Domain Of The Account Having Resource Based Delegation On This Account
435 | $accountDelegatedForThisResourceFromADDomainNBT = $null
436 | $accountDelegatedForThisResourceFromADDomainNBT = $accountDelegatedForThisResource.SubString(0, $accountDelegatedForThisResource.IndexOf("\"))
437 |
438 | # Get The sAMAccountName Of The Account Having Resource Based Delegation On This Account
439 | $accountDelegatedForThisResourceAccountName = $null
440 | $accountDelegatedForThisResourceAccountName = $accountDelegatedForThisResource.SubString($accountDelegatedForThisResource.IndexOf("\") + 1)
441 |
442 | # Retrieve The AD Data Of The Object
443 | $accountDelegatedForThisResourceObject = $null
444 | $accountDelegatedForThisResourceObject = Get-ADObject -Filter "sAMAccountName -eq '$accountDelegatedForThisResourceAccountName'" -Server $accountDelegatedForThisResourceFromADDomainNBT
445 |
446 | # Get The Object Type/Class Of The Account Having Resource Based Delegation On This Account
447 | $accountDelegatedForThisResourceObjectClass = $null
448 | $accountDelegatedForThisResourceObjectClass = $accountDelegatedForThisResourceObject.ObjectClass
449 |
450 | # Get The DN Of The Account Having Resource Based Delegation On This Account
451 | $accountDelegatedForThisResourceDN = $null
452 | $accountDelegatedForThisResourceDN = $accountDelegatedForThisResourceObject.DistinguishedName
453 |
454 | # Get The FQDN Of The AD Domain Of The Account Having Resource Based Delegation On This Account
455 | $accountDelegatedForThisResourceFromADDomainFQDN = $null
456 | $accountDelegatedForThisResourceFromADDomainFQDN = $accountDelegatedForThisResourceDN.Substring($accountDelegatedForThisResourceDN.IndexOf("DC=")).Replace(",DC=",".").Replace("DC=","")
457 |
458 | # Add To The List Of Accounts Having Resource Based Delegation On This Account, With Additional Information
459 | $accountsDelegatedForThisResourceList += "$accountDelegatedForThisResource (Account Type: $accountDelegatedForThisResourceObjectClass) (AD Domain: $accountDelegatedForThisResourceFromADDomainFQDN)"
460 | }
461 | $accountsDelegatedForThisResourceList = $accountsDelegatedForThisResourceList -join ",`n"
462 | } Else {
463 | $accountsDelegatedForThisResourceList = "No-Res-Deleg"
464 | }
465 |
466 | # Display Some Info On Screen So That It Is Visible Something Is Happening
467 | Logging " # $($totalAccounts.ToString().PadLeft($lengthOfUpperValueTotalAccounts, '0')) Of $allAuthSecurityPrincipalsCount - Processing Account '$adDomainFQDN\$sAMAccountName' ($accountType)..." "REMARK"
468 | Logging "" "REMARK"
469 |
470 | # Create An Object Entry For The Account And Add It To The Total List
471 | $accountEntry = New-Object -TypeName System.Object
472 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain FQDN" -Value $adDomainFQDN
473 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain NBT" -Value $adDomainNBT
474 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Domain DN" -Value $adDomainDN
475 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Sam Account Name" -Value $sAMAccountName
476 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Account Name" -Value $accountName
477 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Account Type" -Value $accountType
478 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Service Principal Name(s)" -Value $spnList
479 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Acc Based Deleg Type" -Value $accountBasedDelegType
480 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Acc Based Deleg To" -Value $accountBasedConstrainedDelegationToList
481 | $accountEntry | Add-Member -MemberType NoteProperty -Name "Res Based Deleg For" -Value $accountsDelegatedForThisResourceList
482 | $accountData += $accountEntry
483 | }
484 | } Else {
485 | Logging "" "REMARK"
486 | Logging " > What The Heck? No Objects? Looks Like It!..." "REMARK"
487 | Logging "" "REMARK"
488 | }
489 |
490 | # Define The End Execution Date And Time For This AD Domain
491 | $endExecDateTimeThisADDomain = $null
492 | $endExecDateTimeThisADDomain = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
493 |
494 | # Calculate The Time Spent For This AD Domain
495 | $timeDiff = $null
496 | $timeDiff = (New-Timespan -Start $(Get-Date $startExecDateTimeThisADDomain) -End $(Get-Date $endExecDateTimeThisADDomain)).TotalMinutes
497 |
498 | Logging "" "REMARK"
499 | Logging " > Finished Processing AD Domain '$adDomainFQDN'..." "REMARK"
500 | Logging " > Start Time...........: $startExecDateTimeThisADDomain" "REMARK"
501 | Logging " > End Time.............: $endExecDateTimeThisADDomain" "REMARK"
502 | Logging " > Duration (Minutes)...: $timeDiff" "REMARK"
503 | Logging "" "REMARK"
504 | }
505 |
506 | # Define The End Execution Date And Time
507 | $execEndDateTimeDisplay = Get-Date -Format "yyyy-MM-dd_HH.mm.ss"
508 | Logging "End Date/Time Script................................: $execEndDateTimeDisplay"
509 | Logging ""
510 |
511 | # Define The Location Of The Report
512 | Logging "CSV Report AD Account Scan (Folder).................: $currentScriptFolderPath"
513 | Logging "CSV Report AD Account Scan (File Name)..............: $outputCSVFileName"
514 | Logging ""
515 |
516 | # Define The Location Of The Log File
517 | Logging "Log File AD Account Scan (Folder)...................: $currentScriptFolderPath"
518 | Logging "Log File AD Account Scan (File Name)................: $logFileName"
519 | Logging ""
520 |
521 | # Sort The Table/List
522 | #$accountDataSorted = $accountData | Sort-Object -Descending:$False -Property "Domain NBT","Account Type","Account Name"
523 |
524 | # Export The Table/List To The CSV File
525 | #$accountDataSorted | Export-Csv -Path $outputCSVFilePath -Force -NoTypeInformation
526 | #$accountDataSorted | Out-GridView
527 | $accountData | Export-Csv -Path $outputCSVFilePath -Force -NoTypeInformation
528 | $accountData | Out-GridView
529 | Write-Host ""
530 | Write-Host "DONE!"
531 | Write-Host ""
--------------------------------------------------------------------------------