PSCertUtils.psm1


Function Get-X509Certificate {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [String] $CertificateUri,
    [Parameter(Mandatory = $False, Position = 1)]
    [String] $ValidationThumbprint,
    [Parameter(Mandatory = $False, Position = 2)]
    [securestring] $CertificatePassword,
    [Parameter(Mandatory = $False, Position = 3)]
    [String] $FriendlyName,
    [Parameter(Mandatory = $False, Position = 4)]
    [Switch] $InSecure
  )

  # Parse CertificateUri as Uri
  $X509CertificateUri = $CertificateUri -as [System.URI]

  # If there is no AbsoluteURI, the URI is using the wrong format
  if ($X509CertificateUri.AbsoluteURI -eq $null) { throw ("Unable to get certificate file from {0}" -f $CertificateUri) }

  # Download Certificate File if the URI given is using HTTP or HTTPS
  if ($X509CertificateUri.AbsoluteURI -ne $null -and $X509CertificateUri.Scheme -match '[http|https]') {

    try {
      # Request certificate from server
      $WebResponse = Invoke-WebRequest -Uri $X509CertificateUri.AbsoluteURI -ErrorAction Stop
    }
    catch {
      throw ('Unable to download certificate file from ["{0}"] - EXCEPTION: {1}' -f $X509CertificateUri.AbsoluteURI, $_.Exception.Message)
    }

    try {
      $X509Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($WebResponse.Content, $CertificatePassword, 'Exportable')
    }
    catch {
      throw("Unable to load Certificate from WebResponse - EXCEPTION: {1}" -f $CertificateFile, $_.Exception.InnerException.Message)
    }

  }
  elseif (Test-Path -Path "$CertificateUri" -PathType Leaf) {
    Write-Verbose -Message ('Loading certificate from file: "{0}".' -f $CertificateUri)
    # Load Certificate from File to X509Certificate2 object
    Try
    {
      $X509Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificateUri, $CertificatePassword, 'Exportable')
    }
    Catch
    {
      throw("Unable to load the certificate from {0} - Exception: {1}" -f $CertificateUri, $_.Exception.InnerException.Message)
    }
  }
  Else
  {
    throw ('Unable to find or download the certificate from "{0}.' -f $CertificateUri)
  }

  If ([String]::IsNullOrWhiteSpace($ValidationThumbprint))
  {
    If (!$InSecure)
    {
      throw("No ValidationThumbprint has been supplied, unable to verify certificate. Use -InSecure parameter to force import without validation.")
    }
    Else
    {
      Write-Warning ('No ValidationThumbprint has been supplied, unable to verify certificate.')
    }
  }
  Elseif ($ValidationThumbprint -ne $X509Certificate.Thumbprint)
  {
    throw("Unable to validate certificate from {0}, thumbprint validation mismatch {1} != {2}" -f $CertificateUri, $ValidationThumbprint, $X509Certificate.Thumbprint)
  }

  $CommonName = Get-X509CommonNameFromSubject -X509Subject $X509Certificate.Subject

  # Set friendly name to a safe version of the common name if none was given
  If ([String]::IsNullOrWhiteSpace($FriendlyName)) {
    $FriendlyName = Get-SafeCertificateAlias $CommonName
  }
  Else {
    $FriendlyName = Get-SafeCertificateAlias $FriendlyName
  }

  # Set the friendly name of the X509CertificateObject
  $X509Certificate.FriendlyName = $FriendlyName

  # Return a PSCustomObject with some information in addition to the X509Certificate object
  return [PSCustomObject] @{
    CommonName = $CommonName
    FriendlyName = $FriendlyName
    Source = $X509CertificateUri
    ValidatedThumbprint = $ValidationThumbprint
    X509Certificate = $X509Certificate
  }

}


Function Export-X509Certificate {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [System.Security.Cryptography.X509Certificates.X509Certificate2] $X509Certificate,
    [Parameter(Mandatory = $False, Position = 1)]
    [String] $CertificateFile = '{0}.crt'-f [System.IO.Path]::GetTempFileName(),
    [Parameter(Mandatory = $False, Position = 2)]
    [Alias('Password', 'Pass', 'SecurePassword')]
    [securestring] $CertificatePassword,
    [Parameter(Mandatory = $False, Position = 3)]
    [Switch] $AddToBundle = $False,
    [Parameter(Mandatory = $False, Position = 4)]
    [Switch] $Force = $False
  )

  if ($X509Certificate.GetType().FullName -ne "System.Security.Cryptography.X509Certificates.X509Certificate2") {
    throw ('Unknown X509Certificate object type: "{0}" expected "System.Security.Cryptography.X509Certificates.X509Certificate2".' -f $X509Certificate.GetType().FullName)
  }

  if (-not $AddToBundle -and -not $Force -and (Test-Path $CertificateFile)) {
    throw('Unable to export X509Certificate to "{0}". File exists and neither Force nor AddToBundle were set.' -f $CertificateFile)
  }

  try {
    if ($AddToBundle) {
        "-----BEGIN CERTIFICATE-----" | Add-Content $CertificateFile -ErrorAction Stop
    }
    else {
        "-----BEGIN CERTIFICATE-----" | Set-Content $CertificateFile -Encoding String -ErrorAction Stop
    }
    [System.Convert]::ToBase64String($X509Certificate.Export('cert', $CertificatePassword), "InsertLineBreaks") | Add-Content $CertificateFile
    "-----END CERTIFICATE-----" | Add-Content $CertificateFile
  }
  catch {
    throw("Unable to export X509Certificate to {0} - {1}" -f $CertificateFile, $_)
  }

  return $CertificateFile
}


Function Export-X509CertificatePfx {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0)]
    [ValidateNotNullOrEmpty()]
    [System.Security.Cryptography.X509Certificates.X509Certificate2] $X509Certificate,
    [Parameter(Mandatory = $False, Position = 1)]
    [String] $CertificateFile = '{0}.pfx'-f [System.IO.Path]::GetTempFileName(),
    [Parameter(Mandatory = $False, Position = 2)]
    [securestring] $CertificatePassword
  )

  if ($X509Certificate.GetType().FullName -ne "System.Security.Cryptography.X509Certificates.X509Certificate2") {
    throw ('Unknown X509Certificate object type: "{0}" expected "System.Security.Cryptography.X509Certificates.X509Certificate2".' -f $X509Certificate.GetType().FullName)
  }

  if (Test-Path -Path $CertificateFile) {
    throw('Unable to export X509Certificate to "{0}". File exists.' -f $CertificateFile)
  }

  try {
    $CertBytes = $X509Certificate.Export('pfx', $CertificatePassword)
    [io.file]::WriteAllBytes($CertificateFile, $CertBytes)
  }
  catch {
    throw ('Unable to export X509Certificate. Exception: {0}' -f $_.Exception.InnerException.Message)
  }

  return $CertificateFile

}


Function Install-X509CertificateToTrustedStores {

  If ($IsLinux) {


  }
  Else {

  }


}