Cogger

pki_export.ps1

Feb 22nd, 2023 (edited)
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. $ErrorActionPreference = "SilentlyContinue"
  2. # Of the 312 lines contained within this script, 66 are comments to explain, and 47 are empty lines. Meaning that only 199 lines are performing impertive operations.
  3.  
  4. function ConvertTo-HexString {
  5.     [CmdletBinding()]
  6.     param (
  7.         # Value to convert
  8.         [Parameter(Mandatory=$true, Position = 0, ValueFromPipeline=$true)]
  9.         [object] $InputObjects,
  10.         # Delimiter between Hex pairs
  11.         [Parameter (Mandatory=$false)]
  12.         [string] $Delimiter = ' ',
  13.         # Encoding to use for text strings
  14.         [Parameter (Mandatory=$false)]
  15.         [ValidateSet('Ascii', 'UTF32', 'UTF7', 'UTF8', 'BigEndianUnicode', 'Unicode')]
  16.         [string] $Encoding = 'Default'
  17.     )
  18.  
  19.     begin {
  20.         function Transform ([byte[]]$InputBytes) {
  21.             [string[]] $outHexString = New-Object string[] $InputBytes.Count
  22.             for ($iByte = 0; $iByte -lt $InputBytes.Count; $iByte++) {
  23.                 $outHexString[$iByte] = $InputBytes[$iByte].ToString('X2')
  24.             }
  25.             return $outHexString -join $Delimiter
  26.         }
  27.  
  28.         ## Create list to capture byte stream from piped input.
  29.         [System.Collections.Generic.List[byte]] $listBytes = New-Object System.Collections.Generic.List[byte]
  30.     }
  31.  
  32.     process
  33.     {
  34.         if ($InputObjects -is [byte[]])
  35.         {
  36.             Write-Output (Transform $InputObjects)
  37.         }
  38.         else {
  39.             foreach ($InputObject in $InputObjects) {
  40.                 [byte[]] $InputBytes = $null
  41.                 if ($InputObject -is [byte]) {
  42.                     ## Populate list with byte stream from piped input.
  43.                     if ($listBytes.Count -eq 0) {
  44.                         Write-Verbose 'Creating byte array from byte stream.'
  45.                         Write-Warning ('For better performance when piping a single byte array, use "Write-Output $byteArray -NoEnumerate | {0}".' -f $MyInvocation.MyCommand)
  46.                     }
  47.                     $listBytes.Add($InputObject)
  48.                 }
  49.                 elseif ($InputObject -is [byte[]])
  50.                 {
  51.                     $InputBytes = $InputObject
  52.                 }
  53.                 elseif ($InputObject -is [string])
  54.                 {
  55.                     $InputBytes = [Text.Encoding]::$Encoding.GetBytes($InputObject)
  56.                 }
  57.                 elseif ($InputObject -is [bool] -or $InputObject -is [char] -or $InputObject -is [single] -or $InputObject -is [double] -or $InputObject -is [int16] -or $InputObject -is [int32] -or $InputObject -is [int64] -or $InputObject -is [uint16] -or $InputObject -is [uint32] -or $InputObject -is [uint64])
  58.                 {
  59.                     $InputBytes = [System.BitConverter]::GetBytes($InputObject)
  60.                 }
  61.                 elseif ($InputObject -is [guid])
  62.                 {
  63.                     $InputBytes = $InputObject.ToByteArray()
  64.                 }
  65.                 elseif ($InputObject -is [System.IO.FileSystemInfo])
  66.                 {
  67.                     if ($PSVersionTable.PSVersion -ge [version]'6.0') {
  68.                         $InputBytes = Get-Content $InputObject.FullName -Raw -AsByteStream
  69.                     }
  70.                     else {
  71.                         $InputBytes = Get-Content $InputObject.FullName -Raw -Encoding Byte
  72.                     }
  73.                 }
  74.                 else
  75.                 {
  76.                     ## Non-Terminating Error
  77.                     $Exception = New-Object ArgumentException -ArgumentList ('Cannot convert input of type {0} to Hex string.' -f $InputObject.GetType())
  78.                     Write-Error -Exception $Exception -Category ([System.Management.Automation.ErrorCategory]::ParserError) -CategoryActivity $MyInvocation.MyCommand -ErrorId 'ConvertHexFailureTypeNotSupported' -TargetObject $InputObject
  79.                 }
  80.  
  81.                 if ($null -ne $InputBytes -and $InputBytes.Count -gt 0) {
  82.                     Write-Output (Transform $InputBytes)
  83.                 }
  84.             }
  85.         }
  86.     }
  87.  
  88.     end {
  89.         ## Output captured byte stream from piped input.
  90.         if ($listBytes.Count -gt 0) {
  91.             Write-Output (Transform $listBytes.ToArray())
  92.         }
  93.     }
  94. }
  95.  
  96. #=====[ Load dynamic variables
  97. #   Gather Computername
  98.     $ComputerName = $env:COMPUTERNAME
  99.  
  100. #   Gather Username
  101.     $LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty USERNAME
  102.     if (!($LoggedOnUser) ) { Write-Host "No user is logged on to $ComputerName" -ForegroundColor Red ; break }
  103.  
  104. #   Gather the Team Members Full Name, instead of First.Last this will read as 'First Last'
  105.     $dom = $env:userdomain
  106.     $usr = $env:username
  107.     $Fullname = ([adsi]"WinNT://$dom/$usr,user").fullname
  108.  
  109. #   Logged in team members document path
  110.     $LoggedPath = "C:\Users\$LoggedOnUser\Documents"
  111.     $OnePath = (Get-ChildItem $LoggedPath -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "OneDrive"}).FullName
  112.    
  113.     $ODPathTest = $1DPath -eq "" -or $1DPath -eq $null
  114.     if($ODPathTest -eq $False){ $1DPath = $LoggedPath + "\" + $OnePath }
  115.     if($ODPathTest -eq  $True){ $1DPath = (Get-ChildItem "C:\Users\$LoggedOnUser" -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "OneDrive - "}).FullName }
  116.  
  117. # OneDrive Service
  118. ##  Get the dynamic service name that we need to check, store as variable.
  119.     $OD_DSync = (Get-Service -Name "OneSyncSvc*" -Exclude "OneSyncSvc").Name
  120. ##  Check the status if the dynamically created service, store as variable.
  121.     $OneDriveService = (get-service $OD_DSync | select Status,Can*).Status
  122. ##  Check with boolean logic to see if the service is running, if it isn't running then we will start the service.
  123.     $ODS_Check = $OneDriveService -eq "Stopped"
  124.     if($ODS_Check -eq $True){ Write-Host("OneDrive is $OneDriveService... Starting Service...") ; Start-Service -Name $OD_DSync }
  125.     if($ODS_Check -eq $False){  Write-Host("OneDrive is $OneDriveService") }
  126.  
  127. #=====[ Outlook encryption certification
  128.  
  129. # Define these variables as null si that we can use them to place dynamic data into
  130. $ExportThumb = $null ; $ExportPath  = $null
  131.  
  132. # Set variable for the the UserDS Path within Certificates
  133. $UserDS_Path = "Microsoft.PowerShell.Security\Certificate::CurrentUser\UserDS"
  134. # Create array within our defined above variable, but only include certificates that come from our London Certificate Authority
  135. $UserDS_arr = get-childitem -Path $UserDS_Path -recurse | Where {$_.Issuer -like "CN=ERMLondonIssuingCA"}
  136. # Take the count of the number of items within the array, but define this as integer not a string
  137. $UserDS_Count = [float]$UserDS_arr.count
  138.  
  139. # Set variable for the the MyCerts Path within Certificates
  140. $MyCert_Path = "Microsoft.PowerShell.Security\Certificate::CurrentUser\My"
  141. # Create array within our defined above variable, but only include certificates that come from our London Certificate Authority
  142. $MyCert_arr = get-childitem -Path $MyCert_Path -recurse | Where {$_.Issuer -like "CN=ERMLondonIssuingCA"}
  143. # Take the count of the number of items within the array, but define this as integer not a string
  144. $MyCert_Count = [float]$MyCert_arr.count
  145.  
  146. # Add the total number of possible indicies so that we can ensure that the loop does not repeat forever
  147. $cerIndexCap = $UserDS_Count + $MyCert_Count + 1
  148. # Create an integer set to zero, so that we can loop the do-until for all possible indicies
  149. $i = 0;
  150. # Create array that we will use to check to see the team member has multiple certificates -- and to find the newest if this applies
  151. [collections.arraylist]$MultiCertArr = @()
  152.  
  153. # Until we reach the total number of indicies, continue this loop
  154.     Do {
  155.  
  156.         # For each item contained within the UserDS Path
  157.         foreach ($Thumb_DS in $UserDS_arr) {
  158.  
  159.             # Find the the Cert has an exportable key
  160.             # If the key is not exportable then this value is false then the indicies does not get added to the possible list of items to select from.
  161.             $IsExportable = ((((get-childitem -Path $UserDS_Path -recurse | Where {$_.Thumbprint -eq $Thumb_DS.Thumbprint}).psobject.properties).Value).CspKeyContainerInfo).Exportable
  162.             # If the key is exportable then collect its thumbprint, collect its Cert path, add these to the a query variable, and then add that query variable to our
  163.             # multicert array.
  164.             if($IsExportable -eq $True){
  165.                 $ExportThumb = $Thumb_DS.Thumbprint;
  166.                 $ExportPath = $UserDS_Path;
  167.                 $PKIcert = get-childitem -Path $ExportPath -recurse | Where {$_.Thumbprint -eq $ExportThumb};
  168.                 $MultiCertArr.Add($PKIcert) > $null  }
  169.             $i++
  170.         }
  171.  
  172.         foreach ($Thumb_MY in $MyCert_arr) {
  173.  
  174.             # Find the the Cert has an exportable key
  175.             # If the key is not exportable then this value is false then the indicies does not get added to the possible list of items to select from.
  176.             $IsExportable = ((((get-childitem -Path $MyCert_Path -recurse | Where {$_.Thumbprint -eq $Thumb_MY.Thumbprint}).psobject.properties).Value).CspKeyContainerInfo).Exportable
  177.             # If the key is exportable then collect its thumbprint, collect its Cert path, add these to the a query variable, and then add that query variable to our
  178.             # multicert array.            
  179.             if($IsExportable -eq $True){
  180.                 $ExportThumb = $Thumb_MY.Thumbprint;
  181.                 $ExportPath = $MyCert_Path;
  182.                 $PKIcert = get-childitem -Path $ExportPath -recurse | Where {$_.Thumbprint -eq $ExportThumb};
  183.                 $MultiCertArr.Add($PKIcert) > $null }
  184.             # increase the index variable by 1
  185.             $i++
  186.         }
  187.  
  188.     } Until ( $i -ge $cerIndexCap );
  189.  
  190.     # if multi cert array contains only a single indicies then we will use that to export the pki
  191.     if( [float]$MultiCertArr.count -eq 1 ){ $PFXcert = $PKIcert }
  192.     # if multi cert array contains
  193.     if( [float]$MultiCertArr.count -eq 0 ){ Write-Host("No certificate found exportable or not") }
  194.     # if multi cert array contains    
  195.     if( [float]$MultiCertArr.count -gt 1 ){ Write-Host("Multiple certs possible within standard criteria...retrieving the newest version of the certificate...")
  196.    
  197.         [collections.arraylist]$oldestDate = @()
  198.         foreach ($divCert in $MultiCertArr) {
  199.             $lateDate = ($divCert).NotAfter.ToString("yyyy")
  200.             $oldestDate.Add($lateDate) > $null
  201.         }
  202.  
  203.         $moTime = ($oldestDate | measure -Maximum).Maximum
  204.         foreach ($divCert in $MultiCertArr) { $lateDate = ($divCert).NotAfter.ToString("yyyy") ; if ($lateDate -eq $moTime) { $PFXcert = $divCert } }    
  205.      }
  206.  
  207. $PFXThumb = $PFXcert.Thumbprint
  208.  
  209. #   Using the janked method of encryption, set dynamic team memember specific variable
  210. #   First.Last is store as a variable
  211.     $CryptCode = $env:username
  212.  
  213. #   Store the first.last variable as an array
  214.     $strArray = $CryptCode.ToCharArray()
  215.  
  216. #   Gather only odd variables from the array
  217.     $strOdd = New-Object System.Collections.ArrayList
  218.     $f=0; $strArray | % { if($f = !$f) { $strOdd.Add("$_") > $null } }
  219.  
  220. #   Gather only even variables from the array
  221.     $strEvn = New-Object System.Collections.ArrayList
  222.     $f=1; $strArray | % { if($f = !$f) { $strEvn.Add("$_") > $null } }
  223.  
  224. #   Split Odd variables from name array to its own array
  225.     $strOdd = $strOdd -replace '(^\s+|\s+$)','' -replace '\s+',' '
  226.     $strOdd = [string]::join("",($strOdd.Split("`n")))
  227.  
  228. #   Split even variables from name array to its own array
  229.     $strEvn = $strEvn -replace '(^\s+|\s+$)','' -replace '\s+',' '
  230.     $strEvn = [string]::join("",($strEvn.Split("`n")))
  231.  
  232. #   Combine Odd and Even variables together to set the first stage of this cipher
  233.     $e_ehx = $strOdd + $strEvn
  234.  
  235. #   Setting the second stage of this cipher, convert the first stage into a hexadecimal.
  236.     $hexconv = ConvertTo-HexString $e_ehx
  237.  
  238. #   Set the final stage of this cipher from hexadecimal to a secure string
  239. ##  Each character in an individuals name will increase the length by 16 characters.
  240. ##  Example. There are 436 characters for a 13 character name
  241. ##  Example. There are 468 characters for a 15 character name
  242.     $pfxEncrypt_Key = $hexconv | ConvertTo-SecureString -AsPlainText -Force
  243.  
  244. # Script to execute a seperate PowerShell instance
  245. $scriptBlock = {
  246. Start-Sleep -Milliseconds 2500
  247.     $title = 'Exporting your private exchange key'
  248.     $SecWar = (Get-Process | Where-Object {$_.MainWindowTitle -eq $title}).MainWindowTitle;
  249.     $SecWarBoo = [bool]($SecWar -eq $null);
  250.  
  251.     Do {
  252.         $secWarID = (Get-Process | Where-Object {$_.MainWindowTitle -eq $title}).Id ; sleep 1;
  253.         $wshell = New-Object -ComObject wscript.shell;
  254.         $wshell.AppActivate($title) ; sleep -Milliseconds 100;
  255.         $wshell.SendKeys('~') ; sleep -Milliseconds 3700;
  256.         $SecWar = (Get-Process | Where-Object {$_.MainWindowTitle -eq $title}).MainWindowTitle;
  257.         $SecWarBoo = [bool]($SecWar -eq $null);
  258.  
  259.     } Until ($SecWarBoo -eq $True);
  260. }  
  261.  
  262. $SaveState = $1DPath + "\" + $env:username + "_PKI.pfx"
  263. #   If the export already exists...then inform the script runner... and then stop the script.
  264. if((Test-Path -Path $SaveState -PathType Leaf) -eq  $false){
  265.  
  266. # New Method
  267. #   Attempt to try the first method of exporting the PKI
  268.     Try{
  269.         #   First method of exporting
  270.         #   Certificate  -  cert:\currentuser\my
  271.         $PFXcert | Export-PfxCertificate -FilePath $SaveState -Password $pfxEncrypt_Key
  272.         Start-Sleep -s 4
  273.         Write-Host("PKI exported successfully! Opening contained directory for confirmation.")
  274.         Explorer.exe $1DPath
  275.        
  276.     } catch {
  277.        
  278.         # If the first method fails -- then we will attempt the second which requires a second script to be run to click through all relevant steps.
  279.         Try{
  280.             # Start a new instance of Windows PowerShell and run the script
  281.             $powershellPath = "$env:windir\system32\windowspowershell\v1.0\powershell.exe"
  282.             $process = Start-Process $powershellPath -NoNewWindow -ArgumentList ("-ExecutionPolicy Bypass -noninteractive -noprofile " + $scriptBlock) -PassThru
  283.             $process.WaitForExit($waitTimeMilliseconds)
  284.  
  285.             # Second method of exporting the pki key
  286.             certutil -user -p $pfxEncrypt_Key -exportpfx $PFXThumb $SaveState > $null
  287.  
  288.             Start-Sleep -Milliseconds 500
  289.             Clear-Host
  290.             Write-Host("PKI exported successfully! Opening contained directory for confirmation.")
  291.             Explorer.exe $1DPath
  292.                
  293.         } catch {
  294.            
  295.             # Export failed -- write an error log, and write output
  296.             Clear-Host
  297.             $SaveState = $1DPath + "\IMPORT_PKI_FAILED.log" ; New-Item  $SaveState
  298.             Write-Host("Export failed -- log written to OneDrive. Please attempt manual export operation diticated within process.")
  299.         }
  300.  
  301.     }
  302.  
  303. } else {
  304.     # File exists...halt
  305.     Clear-Host
  306.     Write-Host("Cannot create export of $env:username as $SaveState already exists..halting script")
  307.  
  308. }
  309. sleep -seconds 3
  310. exit
  311.  
Tags: powershell
Add Comment
Please, Sign In to add comment