-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.html
More file actions
565 lines (484 loc) · 22.6 KB
/
README.html
File metadata and controls
565 lines (484 loc) · 22.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
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
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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
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
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Certificate Export Script - README</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 900px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.1em;
opacity: 0.95;
}
.content {
padding: 40px;
}
h2 {
color: #667eea;
margin-top: 30px;
margin-bottom: 15px;
border-bottom: 2px solid #667eea;
padding-bottom: 10px;
}
h3 {
color: #764ba2;
margin-top: 20px;
margin-bottom: 10px;
}
p {
margin-bottom: 15px;
text-align: justify;
}
ul,
ol {
margin-left: 20px;
margin-bottom: 15px;
}
li {
margin-bottom: 8px;
}
code {
background: #e8f4f8;
border: 1px solid #667eea;
border-radius: 3px;
padding: 2px 6px;
font-family: 'Courier New', Courier, monospace;
font-size: 0.95em;
color: #1a3a52;
font-weight: 500;
}
.code-block {
background: #2d2d2d;
color: #f8f8f2;
padding: 20px;
border-radius: 5px;
overflow-x: auto;
margin: 15px 0;
font-family: 'Courier New', Courier, monospace;
font-size: 0.9em;
line-height: 1.5;
}
.code-block code {
background: none;
border: none;
padding: 0;
color: inherit;
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 20px 0;
}
.feature-card {
background: #f9f9f9;
border-left: 4px solid #667eea;
padding: 15px;
border-radius: 5px;
}
.feature-card h4 {
color: #667eea;
margin-bottom: 10px;
}
.parameter {
background: #f9f9f9;
border-left: 4px solid #764ba2;
padding: 12px;
margin: 10px 0;
border-radius: 3px;
}
.parameter strong {
color: #764ba2;
}
.warning {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 5px;
padding: 15px;
margin: 20px 0;
}
.warning::before {
content: "⚠️ ";
font-weight: bold;
}
.success {
background: #d4edda;
border: 1px solid #28a745;
border-radius: 5px;
padding: 15px;
margin: 20px 0;
}
.success::before {
content: "✅ ";
font-weight: bold;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th,
td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background: #667eea;
color: white;
}
tr:hover {
background: #f5f5f5;
}
.footer {
background: #f5f5f5;
padding: 20px;
text-align: center;
color: #666;
border-top: 1px solid #ddd;
font-size: 0.9em;
}
em {
color: #764ba2;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔐 Certificate Export Script</h1>
<p>Bulk export user certificates from Windows Certificate Store to PFX files</p>
</div>
<div class="content">
<h2>Complete SFA Certificate Workflow</h2>
<p>
This script is the <strong>first step</strong> in a three-stage SFA certificate distribution system:
</p>
<div
style="background: #f0f7ff; border: 2px solid #667eea; border-radius: 8px; padding: 20px; margin: 20px 0;">
<h3 style="color: #667eea; margin-top: 0;">📋 Stage 1: Export Certificates</h3>
<p><strong>Script:</strong> <code>Export-UserCertificates.ps1</code></p>
<p><strong>Purpose:</strong> Extract user certificates from Windows Certificate Store</p>
<ul>
<li>Reads user names from <code>userList.txt</code></li>
<li>Queries Active Directory for domain usernames</li>
<li>Exports newest certificate per user as PFX files</li>
<li>Protects with per-user passwords (username = password)</li>
<li>Organizes in timestamped output directory</li>
<li>Generates summary report of successes/failures</li>
</ul>
<p><strong>Format for userList.txt:</strong></p>
<div class="code-block"><code>John Doe<br>
Jane Smith<br>
Alice Johnson<br>
Hyun Young</code></div>
<p><em>Each name on a separate line, matching exactly as it appears in Windows Certificate Store (CN field)</em></p>
<p><strong>Output:</strong> PFX files in <code>exports_TIMESTAMP/</code> directory</p>
</div>
<div
style="background: #fff0f5; border: 2px solid #764ba2; border-radius: 8px; padding: 20px; margin: 20px 0;">
<h3 style="color: #764ba2; margin-top: 0;">📦 Stage 2: Publish to Branches</h3>
<p><strong>Script:</strong> <code>Publish-SFACertificates.ps1</code></p>
<p><strong>Purpose:</strong> Distribute exported certificates to 24 branch servers</p>
<ul>
<li><strong>Pre-flight Connectivity Check:</strong> Automatically validates all branch paths are accessible before publishing</li>
<li>If any branches are unreachable, displays them to the user and prompts whether to continue with only accessible branches</li>
<li>Reads PFX files from <code>exports_TIMESTAMP/</code> directory</li>
<li>Maps each certificate to its target branch server via UNC paths</li>
<li>Copies only active (non-expired) certificates</li>
<li>Skips duplicates already present on remotes</li>
<li>Generates detailed success/failure reports</li>
</ul>
<p><strong>Output:</strong> Certificates distributed to all 24 SFA branches worldwide</p>
</div>
<div
style="background: #f0fff4; border: 2px solid #28a745; border-radius: 8px; padding: 20px; margin: 20px 0;">
<h3 style="color: #28a745; margin-top: 0;">🧹 Stage 3: Archive Expired Certificates</h3>
<p><strong>Script:</strong> <code>Move-ExpiredUserCertificates.ps1</code></p>
<p><strong>Purpose:</strong> Automatically clean up expired certificates</p>
<ul>
<li>Runs on local source before publishing (removes old exports)</li>
<li>Runs on each remote branch after certificates copied (removes old branch certs)</li>
<li>Scans filenames for YYYYMMDD date format</li>
<li>Moves expired certs to <code>Old/</code> subfolder for archival</li>
<li>Ensures only current certificates remain in production</li>
</ul>
<p><strong>Output:</strong> Archive folders with expired certificates on all systems</p>
</div>
<h3>Complete Workflow Example</h3>
<div class="code-block"><code># Step 1: Export certificates from local Windows Certificate Store
.\Export-UserCertificates.ps1
# Creates: exports_2025-12-29_143022/ with PFX files
# Step 2: Publish to all 24 branch servers
.\Publish-SFACertificates.ps1 -LocalSourceDirectory 'C:\Users\admin-sfa\Desktop\SFA Certificates'
# Distributes PFX files to all branches and cleans up expired ones
# The workflow is now complete - all branches have current certificates!</code></div>
<h2>Key Features</h2>
<div class="feature-grid">
<div class="feature-card">
<h4>🗂️ Batch Processing</h4>
<p>Export multiple user certificates in a single run from a user list file</p>
</div>
<div class="feature-card">
<h4>🔍 AD Integration</h4>
<p>Automatically query Active Directory for user sAMAccountName (username)</p>
</div>
<div class="feature-card">
<h4>🔑 Smart Passwords</h4>
<p>Use per-user usernames as passwords or fallback to a global password</p>
</div>
<div class="feature-card">
<h4>💻 Remote Execution</h4>
<p>Export certificates from remote computers via PowerShell remoting</p>
</div>
<div class="feature-card">
<h4>⏱️ Timestamped Exports</h4>
<p>All exports organized in timestamped directories for easy tracking</p>
</div>
<div class="feature-card">
<h4>📊 Detailed Reporting</h4>
<p>Comprehensive summary file tracking all successful and failed exports</p>
</div>
</div>
<h2>Pre-flight Connectivity Check</h2>
<p>
<code>Publish-SFACertificates.ps1</code> includes an automated pre-flight connectivity check that runs immediately
before publishing certificates:
</p>
<ul>
<li>Tests connectivity to all 24+ branch server paths</li>
<li>Displays accessible and inaccessible branches with emoji indicators (✅/❌)</li>
<li>If <strong>all branches are accessible:</strong> Automatically continues without prompting</li>
<li>If <strong>any branches are inaccessible:</strong>
<ul>
<li>Shows a list of unreachable branches</li>
<li>Prompts: "Do you want to continue with the remaining X accessible branch(es)?"</li>
<li>User must explicitly confirm by entering <strong>'yes'</strong> or <strong>'y'</strong></li>
<li>Any other response aborts cleanly without making changes</li>
</ul>
</li>
</ul>
<p>
This ensures administrators are always aware of connectivity issues before the publication process begins,
preventing partial failures and wasted effort.
</p>
<h2>Usage</h2>
<h3>Basic Usage</h3>
<p>Run with default settings (reads from <code>userList.txt</code> in the script directory):</p>
<div class="code-block"><code>.\Export-UserCertificates.ps1</code></div>
<h3>With Username Mapping File</h3>
<p>Provide a CSV file mapping full names to domain usernames:</p>
<div class="code-block"><code>.\Export-UserCertificates.ps1 -UsernameListFile 'usernames.csv'</code></div>
<h3>Remote Computer Export</h3>
<p>Export certificates from a remote computer:</p>
<div class="code-block">
<code>.\Export-UserCertificates.ps1 -ComputerName 'RemotePC' -Credential (Get-Credential)</code>
</div>
<h3>Custom Output Directory</h3>
<p>Specify where to save the exported certificates:</p>
<div class="code-block"><code>.\Export-UserCertificates.ps1 -OutputDirectory 'C:\Certificates'</code></div>
<h2>Parameters</h2>
<div class="parameter">
<strong>-UserListFile</strong><br>
Path to a text file containing user full names (one per line). Defaults to <code>userList.txt</code> in
the script directory.
</div>
<div class="parameter">
<strong>-UserNames</strong><br>
Array of specific user full names to process. If provided, <code>UserListFile</code> is ignored.<br>
<em>Example: </em><code>-UserNames 'John Doe', 'Jane Smith'</code>
</div>
<div class="parameter">
<strong>-ComputerName</strong><br>
Remote computer to connect to. If not specified, exports from the local machine.
</div>
<div class="parameter">
<strong>-Credential</strong><br>
PSCredential object for remote connection. Only used with <code>ComputerName</code>.
</div>
<div class="parameter">
<strong>-CertificateStore</strong><br>
Certificate store to search: <code>'LocalMachine'</code>, <code>'CurrentUser'</code>, or
<code>'Both'</code>. Defaults to <code>'CurrentUser'</code>.
</div>
<div class="parameter">
<strong>-OutputDirectory</strong><br>
Directory to save exported PFX files. Defaults to the script's current directory.
</div>
<div class="parameter">
<strong>-Password</strong><br>
SecureString password to protect exported PFX files. If not provided, prompts user at runtime.
</div>
<div class="parameter">
<strong>-UsernameListFile</strong><br>
Path to CSV file mapping full names to domain usernames. Format: <code>FullName,Username</code><br>
<em>Example: </em><code>John Doe,jdoe</code>
</div>
<div class="parameter">
<strong>-UseUsernameAsPassword</strong><br>
Use domain username as password for each certificate. <strong>Enabled by default.</strong> Requires
either <code>UsernameListFile</code> or <code>QueryActiveDirectory</code>.
</div>
<div class="parameter">
<strong>-QueryActiveDirectory</strong><br>
Query Active Directory for usernames by Display Name. <strong>Enabled by default.</strong> Requires
ActiveDirectory module and domain connectivity.
</div>
<div class="parameter">
<strong>-ADServer</strong><br>
Specific Active Directory server to query. Optional; uses default DC if not specified.
</div>
<h2>Certificate Filename Convention</h2>
<p>Exported certificates follow this naming pattern:</p>
<div class="code-block"><code>FullName - Username - YYYYMMDD.pfx</code></div>
<p><em>Example:</em> <code>John Doe - jdoe - 20271201.pfx</code></p>
<h2>Password Management</h2>
<h3>Per-User Passwords</h3>
<p>When <code>-UseUsernameAsPassword</code> is enabled (default):</p>
<ul>
<li>Each user's certificate is protected with their AD username as the password</li>
<li>Filename shows the username: <code>John Doe - jdoe - 20271201.pfx</code></li>
<li>Certificate opens with password: <code>jdoe</code></li>
</ul>
<h3>Fallback Password</h3>
<p>For users not found in AD or without username mapping:</p>
<ul>
<li>Certificate protected with fallback password (prompted at runtime)</li>
<li>Filename shows "Fallback": <code>Hyun Young - Fallback - 20271201.pfx</code></li>
<li>Summary file clearly marks these for manual follow-up</li>
</ul>
<h2>Interactive Username Prompts</h2>
<p>If AD query finds some usernames but not all, the script prompts for missing ones:</p>
<div class="code-block"><code>⚠️ Found 1 user(s) without username mapping:
• Hyun Young
📝 Please provide the domain username (sAMAccountName) for each user:
Username for 'Hyun Young' (or press Enter to skip): hchung
✅ Added: Hyun Young => hchung</code></div>
<p>You can provide usernames or press Enter to skip (uses fallback password instead).</p>
<h2>Export Summary</h2>
<p>The script generates a detailed <code>export_summary.txt</code> file in the export directory:</p>
<ul>
<li><strong>Failed Exports</strong> - Listed at top and bottom for easy reference</li>
<li><strong>Fallback Password Users</strong> - Clearly marked as requiring manual attention</li>
<li><strong>Per-User Password Users</strong> - Listed with their usernames and expiration dates</li>
</ul>
<h2>Console Output</h2>
<p>The script provides real-time feedback with emoji-enhanced messaging:</p>
<ul>
<li>✅ Green: Successfully exported with per-user password</li>
<li>⚠️ Yellow: Exported with fallback password (needs manual action)</li>
<li>❌ Red: Failed to export</li>
</ul>
<h2>Examples</h2>
<h3>Example 1: Basic Batch Export</h3>
<p>Create <code>userList.txt</code> with:</p>
<div class="code-block"><code>John Doe
Jane Smith
Alice Johnson</code></div>
<p>Run:</p>
<div class="code-block"><code>.\Export-UserCertificates.ps1</code></div>
<h3>Example 2: CSV Username Mapping</h3>
<p>Create <code>usernames.csv</code> with:</p>
<div class="code-block"><code>John Doe,jdoe
Jane Smith,jsmith
Alice Johnson,ajohnson</code></div>
<p>Run:</p>
<div class="code-block">
<code>.\Export-UserCertificates.ps1 -UsernameListFile 'usernames.csv' -QueryActiveDirectory:$false</code>
</div>
<h3>Example 3: Remote Export with Custom Password</h3>
<div class="code-block">
<code>$cred = Get-Credential
$password = ConvertTo-SecureString 'MySecurePassword' -AsPlainText -Force
.\Export-UserCertificates.ps1 -ComputerName 'RemotePC' -Credential $cred -Password $password -UseUsernameAsPassword:$false</code>
</div>
<h2>Prerequisites</h2>
<ul>
<li>PowerShell 5.1 or higher (Windows PowerShell or PowerShell 7+)</li>
<li><strong>For AD queries:</strong> ActiveDirectory module (RSAT-AD-PowerShell on Windows)</li>
<li>Domain connectivity (for AD username lookup)</li>
<li>User certificates must be present in the specified certificate store</li>
<li><strong>For remote execution:</strong> PowerShell remoting enabled on target computer</li>
</ul>
<h2>Troubleshooting</h2>
<h3>Active Directory Module Not Found</h3>
<div class="warning">
If the ActiveDirectory module is not available, the script will fall back to manual password entry and
disable username-based password protection.
</div>
<h3>Certificates Not Found</h3>
<p>
The script searches for certificates by matching the user's full name in the certificate's Subject (CN
field).
Ensure the certificate's "Issued To" field matches exactly with the name in your user list.
</p>
<h3>Remote Export Fails</h3>
<p>
Verify that PowerShell remoting is enabled on the target computer and that you have appropriate
credentials and permissions.
</p>
<h3>Password Not Working</h3>
<p>
Check the export summary file to confirm which password type was used (per-user username vs fallback).
For users with fallback passwords, use the fallback password provided during the export run.
</p>
<h2>Testing Passwords</h2>
<p>
Use the companion script <code>Test-CertificatePasswords.ps1</code> to verify that exported certificates
can be opened with their expected passwords:
</p>
<div class="code-block"><code>.\Test-CertificatePasswords.ps1 -ExportDirectory 'path/to/exports'</code>
</div>
<h2>Best Practices</h2>
<ul>
<li>Always verify the export summary file after running the export</li>
<li>Keep a record of the fallback password used for each export batch</li>
<li>Test exported certificates with <code>Test-CertificatePasswords.ps1</code> before distributing</li>
<li>Follow up manually with users whose certificates used fallback passwords</li>
<li>Store exports in a secure location with appropriate access controls</li>
<li>Use unique fallback passwords for different export batches</li>
</ul>
<h2>Support & Issues</h2>
<p>
For issues or questions, check the export summary file first as it contains detailed information about
which certificates exported successfully and which ones need attention. The summary clearly marks users
whose certificates are using fallback passwords and require manual password configuration.
</p>
</div>
<div class="footer">
<p>Export-UserCertificates.ps1 | Certificate Export Automation Tool</p>
<p>For use with Windows Certificate Store and Active Directory integration</p>
</div>
</div>
</body>
</html>