PS-CryptoStudio.Psm1

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
Function New-RootSubCA
    {
    <#
    .SYNOPSIS
             Creates a two tier PKI CA.
             Version 2.1.0.4
 
    .DESCRIPTION
             Creates a root certificate and two subordinate certificates (SubCa)
 
    .PARAMETER RootKeyLength
            Specifies the length of the Root CA key-values are 1, 2, 4, 8, 16
 
    .PARAMETER SubCA01KeyLength
            Specifies the length of the the first Sub CA key-values are 1, 2, 4, 8, 16
     
    .PARAMETER SubCA02KeyLength
            Specifies the length of the the second Sub CA key-values are 1, 2, 4, 8, 16
     
    .PARAMETER RootDaysValid
            Specifies the number of days the Root Ca is valid for-values are between 30-1825. Default is 365 if not specified
 
    .PARAMETER SubCa01DaysValid
            Specifies the number of days the SubCa01 is valid for-values are between 30-1825-Must be equal or less than Rootdays-This value will be automatically changed if needed. Default is 365 if not specified
 
    .PARAMETER SubCa02DaysValid
            Specifies the number of days the SubCa02 is valid for-values are between 30-1825-Must be equal or less than Rootdays-This value will be automatically changed if needed. Default is 365 if not specified
 
    .EXAMPLE
            PS> New-RootSubCa -RootKeyLength 4 -SubCA01KeyLength 4 -SubCA02KeyLength 4 -RootDaysValid 400 -SubCa01DaysValid 365 -SubCa02DaysValid 300
 
    .INPUTS
            None.
 
    .NOTES
            Requirements: Windows 10 17.09 or better or Server 2016 or better
            Requirements: Windows PowerShell 5.1
 
            Max Encrypt size RSA ((KeySize - 384) / 8) + 37
                             
    #>
    [CmdletBinding()]
    Param(
       [Parameter(Mandatory=$True)]
       [ValidateSet("1", "2", "4", "8", "16")]
       [Int]$RootKeyLength,
 
       [Parameter(Mandatory=$True)]
       [ValidateSet("1", "2", "4", "8", "16")]
       [Int]$SubCA01KeyLength,
 
       [Parameter(Mandatory=$True)]
       [ValidateSet("1", "2", "4", "8", "16")]
       [Int]$SubCA02KeyLength,
 
       [Parameter(Mandatory=$False)]
       [ValidateRange(30,1825)]
       [Int]$RootDaysVaild,
 
       [Parameter(Mandatory=$False)]
       [ValidateRange(30,1825)]
       [Int]$SubCa01DaysValid,
 
       [Parameter(Mandatory=$False)]
       [ValidateRange(30,1825)]
       [Int]$SubCa02DaysValid
 
       )
 
  $WarningPreference = "Continue"
# Set days equal to one year (365) if not provided.
  If ($RootDaysVaild -eq 0) {$RootDaysVaild =365}
  If ($SubCa01DaysValid -eq 0) {$SubCa01DaysValid=365}
  If ($SubCa02DaysValid -eq 0) {$SubCa02DaysValid=365}
 
# Ensure that RootDays is greater than SubCaxDays
  If ($RootDaysVaild -lt $SubCa01DaysValid) {$SubCa01DaysValid =$RootDaysVaild;Write-Warning "SubCa01 validty date has been changed to $RootDaysVaild"}
  If ($RootDaysVaild -lt $SubCa02DaysValid) {$SubCa02DaysValid =$RootDaysVaild;Write-Warning "SubCa02 validty date has been changed to $RootDaysVaild"}
 
  $CertIssuerMatch="CryptoStudio_RooTCA";$CertSub="PS-Crypto_SubCa"
 
# Declare functions
  Function Get-Password ($CertName)
    {
       $ChkSecure=0
     Do
       {
        $SecurePassword = Read-Host -Prompt "Enter password for $CertName" -AsSecureString
        $SecurePassword2 = Read-Host -Prompt "Please verify password for $CertName" -AsSecureString
        If ([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)) -eq [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword2)))
           {
            $ChkSecure=1
           }
 
       Else
          {
           $ChkSecure=0
           Write-Host "Passwords do not match" -ForegroundColor Red
          }
             
       } While ($ChkSecure -eq 0)
       Return $SecurePassword
 
    }
# End function declaration
   
# Check to see if PS-CryptoStudio is already installed
  If ( (Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Issuer -match $CertIssuerMatch} | Where-Object {$_.Subject -match $CertSub} ))
    {
     Write-Host "Error-PowerShell CryptoStudio RootSubCa already installed." -ForegroundColor Red
     Break
    }
 
# Check if run as administrator
  If (! ((New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )))
      {
       Write-Host "Not running as administrator`nRerun with administrative privilages" -ForegroundColor Red
       Break
      }
 
# Check OS version
  $OSInfo = Get-WmiObject -class Win32_OperatingSystem
  If ([INT]$OSVersion=($OSInfo.Version).Substring(0,2) -lt 10)
      {
       Write-Host "Invalid Operating System`nWindows 10 or Server 2016 or greater" -ForegroundColor Red
       Break
      }
 
# Confirm before continuing
  $Read=Read-Host "This will install a Root-SubCa(x2)-`'c`' to continue-Anything else aborts"
  If ($Read -ne "c" -or $Read -ne "C")
      {
       Write-Host "Exiting" -ForegroundColor Cyan
       Break
      }
 
# Get domain name, if any
  $DNSRoot=$Null
  If ($env:USERDNSDOMAIN)
    {
     $DNSRoot="." + $env:USERDNSDOMAIN
    }
   
# Define variables-force revalidation.
  [ValidateRange(0, 16384)]$RootKeyLength = $RootKeyLength * 1024
  [ValidateRange(0, 16384)]$SubCA01KeyLength = $SubCA01KeyLength * 1024
  [ValidateRange(0, 16384)]$SubCA02KeyLength = $SubCA02KeyLength * 1024
 
  Clear-Host
 
# Get passwords for certs
  $RootCertPWD = Get-Password "Root Cert"
  $SubCa01PWD = Get-Password "SubCa-01"
  $SubCa02PWD = Get-Password "SubCa-02"
  
# CertStore Variables
  $SourceStoreScope = 'LocalMachine';$SourceStorename = 'My';$DestStoreScope = 'LocalMachine';$DestStoreName = 'root'
  $CertStore="$Env:UserProfile\Documents\MyCerts";$CertStorePublic=$CertStore + "\Public";$CertStorePrivate=$CertStore + "\Private"
  $CertStoreCSR=$CertStore + "\CSR"
  $AESPath = "$CertStore\AES"; $AESKeyPath="$CertStore\AES\Type-001.TeeStar";$CertEncStore=$CertStore + "\Enc"
 
# Root Variables
  $RootFriendlyName="PS-Crypto_RooT-01";$Subject="PS-CryptoStudio_RooTCA";$RootCert="PS-Crypto_RootCert.Cer";$RootPrivateName="PS-Crypto_RootCert.Pfx"
  $FullDNSName=$env:COMPUTERNAME + $DNSRoot;$CertTumbPrint=$null
  [DateTime]$RootVaild= ((Get-Date).AddDays($RootDaysVaild))
 
# SubCA01 Variables
  $SubFriendlyName01="PS-Crypto_SubCa-01";$SubCertName01="PS-Crypto_SubCert01.Cer";$SubCertPrivateName01="PS-Crypto_SubCert01.Pfx"
  $SubCaSubject01="PS-Crypto_SubCa-01"
  [DateTime]$SubCA01Vaild= ((Get-Date).AddDays($SubCa01DaysValid))
 
# SubCA02 Variables
  $SubFriendlyName02="PS-Crypto_SubCa-02";$SubCertName02="PS-Crypto_SubCert02.Cer";$SubCertPrivateName02="PS-Crypto_SubCert02.Pfx"
  $SubCaSubject02="PS-Crypto_SubCa-02"
  [DateTime]$SubCA02Vaild= ((Get-Date).AddDays($SubCa02DaysValid))
   
# Create CertStore Directories
  New-Item $CertStorePublic -ItemType Directory -Force |Out-Null
  New-Item $CertStorePrivate -ItemType Directory -Force |Out-Null
  New-Item $AESPath -ItemType Directory -Force |Out-Null
  New-Item $CertStoreCSR -ItemType Directory -Force |Out-Null
 
  Clear-Host
#
# Create New Root Certificate
#
  Write-Host "Generating Root Certificate-Keylength $RootKeyLength Friendly Name-$RootFriendlyName. Valid untill $RootVaild" -ForegroundColor Cyan
  $Elapsed = [System.Diagnostics.Stopwatch]::StartNew()
  $Root= New-SelfSignedCertificate -KeyUsage KeyEncipherment, DataEncipherment, CertSign -NotAfter $RootVaild -HashAlgorithm SHA256 -KeyUsageProperty All -TextExtension @("2.5.29.19 ={critical} {text}ca=1&pathlength=3") -KeyLength $RootKeyLength -FriendlyName $RootFriendlyName -Subject $Subject -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -certstorelocation cert:\localmachine\My -dnsname $FullDNSName
  $CertTumbPrint=$Root.Thumbprint
  Write-Host "Created Root certificate in-: $($Elapsed.Elapsed.ToString())" -ForegroundColor Green
#
# Place public certificate in Root
  Export-Certificate -Cert $Root -FilePath $CertStorePublic\$RootCert -Type CERT -Force | Out-Null
  $Root|Export-PfxCertificate -FilePath "$CertStorePrivate\$RootPrivateName" -Password $RootCertPWD | Out-Null
   
  Import-Certificate -FilePath $CertStorePublic\$RootCert -CertStoreLocation cert:\LocalMachine\Root |Out-Null
  Get-ChildItem Cert:\LocalMachine\CA | Where-Object {$_.Thumbprint -eq $CertTumbPrint} | Remove-Item -Force
  Write-Host "Root certificate with thumbprint->$CertTumbPrint installed in Root`n" -ForegroundColor Green
#
# Create New Subordinate Certificate-001
#
  Write-Host "Creating Subordinate Certificate01-Keylength $SubCA01KeyLength Friendly Name-$SubFriendlyName01. Valid untill $SubCA01Vaild" -ForegroundColor Cyan
  $Elapsed = [System.Diagnostics.Stopwatch]::StartNew()
  $SubCert01= New-SelfSignedCertificate -KeyUsage KeyEncipherment, DataEncipherment, CertSign -NotAfter $SubCA01Vaild -KeyUsageProperty All -HashAlgorithm SHA256 -TextExtension @("2.5.29.19 = {critical} {text}ca=1&pathlength=0") -Subject $SubCaSubject01 -KeyLength $SubCA01KeyLength -Signer $Root -FriendlyName $SubFriendlyName01 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -certstorelocation cert:\localmachine\my -dnsname $FullDNSName9
  $SubCA01Thumbprint=$SubCert01.Thumbprint
  Get-ChildItem Cert:\LocalMachine\CA | Where-Object {$_.Thumbprint -eq $SubCA01Thumbprint} | Remove-Item -Force
  Write-Host "Created SubCert01 in-: $($Elapsed.Elapsed.ToString())" -ForegroundColor Green
#
# Place public certificate in CA Store (Intermediate Certification Authorities)
  Export-Certificate -Cert $SubCert01 -FilePath $CertStorePublic\$SubCertName01 -Type CERT -Force | Out-Null
  $SubCert01|Export-PfxCertificate -FilePath "$CertStorePrivate\$SubCertPrivateName01" -Password $SubCa01PWD | Out-Null
  Import-Certificate -FilePath "$CertStorePublic\$SubCertName01" -CertStoreLocation Cert:\LocalMachine\CA |Out-Null
  Write-Host "SubCA01 certificate with thumbprint->$SubCA01Thumbprint installed in CA Store (Intermediate Certification Authorities) `n" -ForegroundColor Green
#
# Create New Subordinate Certificate-002
#
  Write-Host "Creating Subordinate Certificate02-Keylength $SubCA02KeyLength Friendly Name-$SubFriendlyName02. Valid untill $SubCA02Vaild" -ForegroundColor Cyan
  $Elapsed = [System.Diagnostics.Stopwatch]::StartNew()
  $SubCert02= New-SelfSignedCertificate -KeyUsage KeyEncipherment, DataEncipherment, CertSign -NotAfter $SubCA02Vaild -KeyUsageProperty All -HashAlgorithm SHA256 -TextExtension @("2.5.29.19 = {critical} {text}ca=1&pathlength=0") -Subject $SubCaSubject02 -KeyLength $SubCA02KeyLength -Signer $Root -FriendlyName $SubFriendlyName02 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -certstorelocation cert:\localmachine\my -dnsname $FullDNSName
  $SubCA02Thumbprint=$SubCert02.Thumbprint
  Get-ChildItem Cert:\LocalMachine\CA | Where-Object {$_.Thumbprint -eq $SubCA02Thumbprint} | Remove-Item -Force
  Write-Host "Created SubCert02 in-: $($Elapsed.Elapsed.ToString())" -ForegroundColor Green
#
# Place public certificate in CA Store (Intermediate Certification Authorities)
  Export-Certificate -Cert $SubCert02 -FilePath $CertStorePublic\$SubCertName02 -Type CERT -Force | Out-Null
  $SubCert02|Export-PfxCertificate -FilePath "$CertStorePrivate\$SubCertPrivateName02" -Password $SubCa02PWD | Out-Null
  Import-Certificate -FilePath "$CertStorePublic\$SubCertName02" -CertStoreLocation Cert:\LocalMachine\CA |Out-Null
  Write-Host "SubCA02 certificate with thumbprint->$SubCA02Thumbprint installed in CA Store (Intermediate Certification Authorities) `n" -ForegroundColor Green
 
# List all created certificates
  Write-Host "`n`nCerts created" -ForegroundColor Magenta
  $Root, $SubCert01, $SubCert02 | Select-Object Subject, Issuer, Thumbprint | Sort-Object -Property Subject
 
    }
 
Function New-HostCert
    {
   <#
    .SYNOPSIS
             Creates certificates for a host using existing PowerShell CryptoStudio RootCA and SubCAs
             Version 2.1.0.4
 
    .DESCRIPTION
             Creates two certificates for a host (using SubCA01 and SubCa02). Stores both public and private keys in Documents\MyCerts folder
 
    .PARAMETER HostName
            Specifies the subject name for the host. This is also included in the Subject Alternate Names (SAN) list.
 
    .PARAMETER SANName
            Specifies the FQDN of the host. Multiple hosts can be declared seperated by commas
     
    .PARAMETER FriendlyName
            Specifies the 'friendly name' of the certificate
 
    .PARAMETER HostKeyLength
            Specifies the length of the Host key- valid values are 1, 2, 4, 8, 16 (to be multiplied by 1K or 1024)
 
    .PARAMETER InstallCertLocal
            Switch to determine if certificates should be installed in local cert store.
 
    .PARAMETER DaysValid
            Number of days the host certificate is valid-values are between 1-1825-Must be equal or less than SubCa0x. The SubCa with the shortest validity period will be selected-This value will be automatically changed if needed. Default is 365 if not specified
 
    .EXAMPLE
            PS> New-HostCert -HostName "myhost.com" -SANName "vpn.myhost.com", "mail.myhost.com", "remote.myhost.com" -FriendlyName "My Test Cert" -HostkeyLength 4 -InstallCertLocal -DaysValid 200
 
    .INPUTS
            None.
 
    .NOTES
            Requirements: Windows 10 17.09 or better or Server 2016 or better
      Requirements: Windows PowerShell 5.1
 
      Max Encrypt size RSA ((KeySize - 384) / 8) + 37
      However, if the optimal asymmetric encryption padding (OAEP) parameter is true, the following can be used to calculate the max bytes: ((KeySize - 384) / 8) + 7
 
     #>
           
     [CmdletBinding()]
param(
    [Parameter( Mandatory=$true)]
    [string]$HostName,
 
    [Parameter( Mandatory=$false)]
    [Array]$SANName,
 
    [Parameter( Mandatory=$true)]
    [string]$FriendlyName,
     
    [Parameter(Mandatory=$True)]
    [ValidateSet("1", "2", "4", "8", "16")]
    [Int]$HostKeyLength,
 
    [Parameter(Mandatory=$False)]
    [Switch]$InstallCertLocal,
 
    [Parameter(Mandatory=$False)]
    [ValidateRange(1,1825)]
    [Int]$DaysVaild
    )
 
  $WarningPreference = "Continue"
# Set Days equal to one year (365) if not provided.
  If ($DaysVaild -eq 0)
    {
     $DaysVaild=365
    }
# Check if run as administrator
  If (! ((New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )))
      {
       Write-Host "Not running as administrator`nRerun with administrative privilages" -ForegroundColor Red
       Break
      }
 
# Check OS version
  $OSInfo = Get-WmiObject -class Win32_OperatingSystem
  If ([INT]$OSVersion=($OSInfo.Version).Substring(0,2) -lt 10)
      {
       Write-Host "Invalid Operating System`nWindows 10 or Server 2016 or greater" -ForegroundColor Red
       Break
      }
 
# Ensure that RootDays is greater than SubCaxDays
  If ($RootDaysVaild -lt $SubCa01DaysValid) {$SubCa01DaysValid =$RootDaysVaild;Write-Warning "Host cert validty date has been changed to $RootDaysVaild"}
#CertStore Variables
  $SourceStoreScope = 'LocalMachine';$SourceStorename = 'My';$DestStoreScope = 'LocalMachine';$DestStoreName = 'root'
  $CertStore="$Env:UserProfile\Documents\MyCerts";$CertStorePublic=$CertStore + "\Public";$CertStorePrivate=$CertStore + "\Private"
  $CertStoreCSR=$CertStore + "\CSR"
  $AESPath = "$CertStore\AES"; $AESKeyPath="$CertStore\AES\Type-001.TeeStar";$CertEncStore=$CertStore + "\Enc"
 
#Cert Variables
  $CertIssuerMatch="CryptoStudio_RooTCA";$CertSub="PS-Crypto_SubCa";$Count=1
  $FriendlyName += "-CryptoStudio"
 
  New-Item $CertStorePublic -ItemType Directory -Force |Out-Null
  New-Item $CertStorePrivate -ItemType Directory -Force |Out-Null
  New-Item $AESPath -ItemType Directory -Force |Out-Null
  New-Item $CertEncStore -ItemType Directory -Force |Out-Null
 
  [ValidateRange(0, 16384)]$HostKeyLength = $HostKeyLength * 1024
  $SANName += $HostName
# Get signing certificates
  $SubCerts= Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Issuer -match $CertIssuerMatch} | Where-Object {$_.Subject -match $CertSub}
# Make sure SubCa exist
  If (! $SubCerts)
      {
       Write-Host "`nCertificate signed by SubCa for $CertSub does not exist!" -ForegroundColor Red
       Break
      }
# Check to see if SubCa is about to expire
  $CertDays=(($SubCerts.NotAfter | Sort-Object | Select-Object -First 1) - (Get-Date)).Days
  If ($CertDays -lt 2)
    {
     Write-Host "SubCa is expired or about to expire" -ForegroundColor Red
     Break
    }
# Make sure that SubCa expires after host cert
  If ($CertDays -lt $DaysVaild)
    {
     $DaysVaild =$CertDays -1
     Write-Warning "Host cert validty date has been changed to $CertDays"
    }
  [DateTime]$CertValid = ((Get-Date).AddDays($DaysVaild))
 
# Check to make sure certifcates can sign
  ForEach ($SubCert in $SubCerts)
      {
       If ($SubCert.Extensions.oid.Value -notcontains "2.5.29.19")
            {
             Write-Host "`nCertificate" ($SubCert.Thumbprint) "is invalid" -ForegroundColor Red
             Break
            }
      }
   
# Get Password for Certs
  Do
      {
       $SecurePassword = Read-Host -Prompt "Enter password for certificates" -AsSecureString
       $SecurePassword2 = Read-Host -Prompt "Please verify password for certificates" -AsSecureString
       If ([Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)) -eq [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword2)))
          {
           $ChkSecure=1
          }
 
       Else
          {
           $ChkSecure=0
           Write-Host "Passwords do not match" -ForegroundColor Red
          }
             
      } While ($ChkSecure -eq 0)
 
# Create computer certificates
  $Count=1;$Certs=@()
  Try
      {
       ForEach ($SubCert in $SubCerts)
          {
           $FriendlyCert=$FriendlyName + "-SubCA-0" + $Count
           Write-Host "Generating Computer Certificate01-Keylength $HostKeyLength Friendly Name-$FriendlyCert" -ForegroundColor Cyan
           $Elapsed = [System.Diagnostics.Stopwatch]::StartNew()
           $CompCert= New-SelfSignedCertificate -KeyUsage KeyEncipherment, DataEncipherment -KeyUsageProperty All -NotAfter $CertValid -HashAlgorithm SHA256 -Subject $HostName -KeyLength $HostKeyLength -Signer $SubCert -FriendlyName $FriendlyCert -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -certstorelocation cert:\localmachine\my -dnsname $SANName
          # Export Public Key
           Export-Certificate -Cert $CompCert -FilePath "$CertStorePublic\$HostName-SubCa0$Count.Cer" -Type CERT -Force | Out-Null
          # Export Private Key
           $CompCert| Export-PfxCertificate -FilePath "$CertStorePrivate\$HostName-SubCa0$Count.Pfx" -Password $SecurePassword | Out-Null
           $Certs +=$CompCert
           Write-Host "Created computer certificate in-:$($elapsed.Elapsed.ToString())" -ForegroundColor Green
           $Count ++
          If ($InstallCertLocal)
            {
             Write-Host "Created computer certificate for $HostName and placed the certificate with the thumbprint->" $CompCert.ThumbPrint " in the Personal store`n`n" -ForegroundColor Green
            }
          Else
            {
             ForEach ($Cert in $Certs)
                {
                # Delete cert
                 Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -contains ($Cert.Thumbprint)} |Remove-Item -Force
                }
            }
        }
 
       Write-Host "`n`nCerts created" -ForegroundColor Magenta
       $Certs | Select-Object Subject, Issuer, Thumbprint | Sort-Object -Property Subject
      }
 
  Catch
      {
       Write-Output "`n`nError creating certificate-Check parameters and try again"
       Break
      }
 
 
 
    }
 
Function Remove-RootSubCA
    {
     <#
    .SYNOPSIS
             Removes RootCA and SubCAs created by New-RootSubCA
             Version 1.0.0.4
 
    .DESCRIPTION
             Removes RootCA and SubCAs created by New-RootSubCA. Also deletes RootCA and SubCAs from MyCerts directory. Does not delete other certificates signed by SubCAs
 
    .EXAMPLE
             PS> Remove-RootSubCA
 
    .INPUTS
             None.
 
    .OUTPUTS
             None.
 
    .NOTES
             Requirements: Windows 10 17.09 or better or Server 2016 or better
       Requirements: Windows PowerShell 5.16
    #>
     
    # Check if run as administrator
     If (! ((New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )))
        {
         Write-Host "Not running as administrator`nRerun with administrative privilages" -ForegroundColor Red
         Break
        }
 
    # Check OS version
       $OSInfo = Get-WmiObject -class Win32_OperatingSystem
     If ([INT]$OSVersion=($OSInfo.Version).Substring(0,2) -lt 10)
        {
         Write-Host "Invalid Operating System`nWindows 10 or Server 2016 or greater" -ForegroundColor Red
         Break
      }
      
    # CertStore Variables
       $SourceStoreScope = 'LocalMachine';$SourceStorename = 'My';$DestStoreScope = 'LocalMachine';$DestStoreName = 'root'
       $CertStore="$Env:UserProfile\Documents\MyCerts";$CertStorePublic=$CertStore + "\Public";$CertStorePrivate=$CertStore + "\Private"
       $CertStoreCSR=$CertStore + "\CSR"
       $AESPath = "$CertStore\AES"; $AESKeyPath="$CertStore\AES\Type-001.TeeStar";$CertEncStore=$CertStore + "\Enc"
    # Cert Variables
       $CertIssuerMatch="CryptoStudio_RooTCA";$CertSub="PS-Crypto_SubCa";$Count=1
       $FriendlyName += "-CryptoStudio"
 
       $Issuer= "PS-CryptoStudio"
       $Certs=Get-ChildItem Cert:\LocalMachine -Recurse | Where-Object {$_.Issuer -match $Issuer}
       $Certs | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue| Out-Null
       Get-ChildItem $CertStorePrivate |Where-Object {($_.Name -match "PS-Crypto_RootCert.Pfx") -or ($_.Name -match "PS-Crypto_SubCert01.Pfx") -or ($_.Name -match "PS-Crypto_SubCert02.Pfx") } | Remove-Item -Force
    }
 
Function Get-CertInfo
    {
     <#
    .SYNOPSIS
             Gets certificate information
             Version 1.0.0.4
 
    .DESCRIPTION
             Gets certificate information from pfx file and returns certificate validity, Subject Name, SAN, Signature Hash Algorithm, Keysize and Issuer. Returns false on errors
 
    .PARAMETER FilePath
             Specifies the location of the pfx file
 
    .EXAMPLE
             PS> Get-Certinfo "C:\Users\User-01\Documents\MyCerts\Private\MyCert.Pfx"
 
    .INPUTS
             None.
 
    .OUTPUTS
             System.Array
 
    .NOTES
             Requirements: Windows 10 17.09 or better or Server 2016 or better
       Requirements: Windows PowerShell 5.1
             
    #>
     [CmdletBinding()]
    Param(
       [Parameter(Mandatory=$True)]
       [String]$FilePath
       )
     Try
        {
         $Cert=Get-PfxCertificate -FilePath $FilePath -ErrorAction Stop
         $SANRaw=($Cert.Extensions | Where-Object {$_.Oid.Value -eq "2.5.29.17"}).Format(0) -split ", "
         $Info= @{
                  CertNotBefore = $Cert.NotBefore
                  CertNotAfter = $Cert.NotAfter
                  Subject = $Cert.Subject
                  SAN = $SANRaw
                  SignatureHashAlgorithm = $Cert.SignatureAlgorithm.FriendlyName
                  PublicKeyExchange = $Cert.PublicKey.Key.KeyExchangeAlgorithm
                  PublicKeySize = $Cert.PublicKey.Key.KeySize
                  Issuer = $Cert.Issuer
 
         }
        # Sort Hashtable
         $Info=$Info.GetEnumerator() | Sort-Object -Property name
         Return $Info
        }
     Catch
        {
         Return $false
        }
    }