


<#
.SYNOPSIS
    Sectigo Certificate Creator
.DESCRIPTION
    Creates a Sectigo Certificate for ITD Organization
.NOTES
    Requires:
    ITD.Infra-Certificate-Internal.Sectigo
.LINK
    https://northdakota.service-now.com/kb_view.do?sysparm_article=KB0018128
#>

[CmdletBinding(DefaultParameterSetName = 'Windows')]
param(
    # Email address for notifications, comma seperated
#    [Parameter(Mandatory, ParameterSetName = 'Windows')]
#    [Parameter(Mandatory, ParameterSetName = 'Cloud Service')]
#    [String]$RequesterEmail,

    # Common Name for cert
    [Parameter(Mandatory, ParameterSetName = 'Windows')]
    [Parameter(Mandatory, ParameterSetName = 'Cloud Service')]
    [String]$CommonName,

    # Comma separated.
    [Parameter(Mandatory, ParameterSetName = 'Windows')]
    [Parameter(Mandatory, ParameterSetName = 'Cloud Service')]
    [String]$SubjectAlternative,

    # Host for Cert Delivery, comma seperated
    [Parameter(Mandatory, ParameterSetName = 'Windows')]
    [String]$DestinationServer,

    # Option for pfx in PasswordState
    [Parameter(Mandatory, ParameterSetName = 'Windows')]
    [bool]$PfxtoPasswordState,

    # AppName CI in CMDB
    [Parameter(Mandatory, ParameterSetName = 'Cloud Service')]
    [String]$ApplicationName
)


process {
    
    
    #Find-Module -Repository ITD_PwshGallery -Name ITD.Infra-Certificate-External.General|Update-Module -Scope CurrentUser
    #exit
    Import-Module ITD.Infra-Certificate-External.General -DisableNameChecking
    Import-Module ITD.Infra-Certificate-External.JsonDB
    

    #We reusing and breaking it up to an array for further use in script
    $DestinationServerArray = $DestinationServer -split ","

    #PSU Reassignment per Zacks standards
    $RequestedBy = $UAJob.Identity.Name # user that started the job
    $PSUJobId = $UAJob.Id
    

    #$Test Mode
    # - Blocks Access to selected users 
    # - Uses Test Environment for ServiceNow Change
    # - Variable can be used for debugging
    $ApprovedTester=@('prvfjpeterson@nd.gov','prvjdkieson@nd.gov')

    if ($test) {
      Write-Verbose -Message "Running in Test Mode " -Verbose
      if ($ApprovedTester -contains $RequestedBy)
      { 
          "You are allowed but others are disabled"
      }
      else {
         Write-Error "Check with freeman script is currenly disabled"
        # exit
      }
    }

    #Set ad Default to Hide from End user. 
    $ServerType="IIS"
    $Format="base64"
    $KeyType="RSA" #reminder this would need to be set on csr.
    $mydate=(Get-Date -Format 'yyyy-MM-dd'|out-string).Trim()
    $FriendlyName = $CommonName + "-" +$myDate

    #Write-Verbose -Message "Update Module" -Verbose
    #Find-Module -Repository ITD_PwshGallery -Name ITD.Infra-Certificate-External.Sectigo |Update-Module -Scope AllUsers


    if ($PSCmdlet.ParameterSetName -eq 'Windows') {
        Write-Verbose -Message "Validate host" -Verbose
        Foreach ($ComputerName in $DestinationServerArray) {
           $remotehi=Invoke-Command -ComputerName $ComputerName -ScriptBlock {"hi"} -Credential $Secret:ndgov_svcitdpsuwin
 
           if ($remotehi -eq "hi") {
             "Connection to host $ComputerName Succeded"
           } else {
             "Connection to host $ComputerName failed"
             exit
           }
        }
    }

        if ($PSCmdlet.ParameterSetName -eq 'Windows') {
            Write-Verbose -Message "Retrieve CI from ServiceNow" -Verbose 
            #We are just pulling appname from first DestinationServer
            New-ITDServiceNowSession -Environment Production -Credential $Secret:snow_vmcred
              $IP=(Resolve-DnsName -Name $DestinationServerArray[0]).IPAddress
              $Filter= "ip_address=$ip^operational_status=1"
              $Fields=("FQDN","ip_address","Location","model_id","Name","dns_domain","os_domain","Schedule","Environment","sys_class_name","u_nd_application_svc","discovery_source","support_group")
              $CI= Get-ITDServiceNowRecord -Table "cmdb_ci_win_server" -Filter $Filter  -Fields $Fields -First 1
              $ApplicationName=$CI.u_nd_application_svc.display_value 
 
             if (!$ApplicationName) {
               write-Error "CI NOT FOUND"
               exit
             }
            $customFields = @(
                [pscustomobject]@{ name = "ApplicationName"; value = $ApplicationName }
            )
        }
        else  { #ParmeterSet Not Windows 
            Write-Verbose -Message "Retrieve App record from ServiceNow" -Verbose

            New-ITDServiceNowSession -Environment Production -Credential $Secret:snow_vmcred
              $Filter= "name=$ApplicationName"
              $Fields=("name")
              $CI= Get-ITDServiceNowRecord -Table "cmdb_ci_service_auto" -Filter $Filter -Fields $Fields

              if ($CI.name.value -ne $ApplicationName ) {
                    Write-Error "Could not find $ApplicationName"
                    exit
          } 
    }


#Got email address now!
$RequesterEmail=Get-ICE-Snowemail -ApplicationName $ApplicationName -Credential $Secret:snow_vmcred

 Send-ICE-Mail -recipientsString $RequesterEmail  -Jobid $PSUJobId  -status "Started"  -Message "Check job status"







    Write-Verbose -Message "Validate Email Address" -Verbose
    $EmailAddressList = $RequesterEmail -split ","
    

    foreach ($e in $EmailAddressList) {
        $user = Get-ADUser -Filter "Mail -eq '$e'" -Properties Mail
        $group = Get-ADGroup -Filter "Mail -eq '$($e)'" -Properties Mail

        if ($user -or $group) {
          Write-Verbose -Message  "$e Passed testing" -Verbose
        }
         else {
                   Write-Error "$e is an invalid email address. Terminating Script"
           exit
        }
    }

    $RequesterEmail=Get-ICE-Snowemail -ApplicationName $ApplicationName -Credential $Secret:snow_vmcred


#Set env prod
Set-JDEnvironment -Name prod


Write-Verbose -Verbose "Retire PreviousThumbprint"
$PreviousThumbprint=(Select-JDJson -TableName certcache -CommonName $commonname).Thumbprint

if ($PreviousThumbprint) {
  $table=@("certlog","certcache")
  Foreach ($t in $table) {
   Set-JDJson -TableName $t `
       -Where { param($row) $row.CommonName -eq $commonname } `
       -Set @{ is_retired = $true; PreviousThumbprint = $PreviousThumbprint } `
       -Verbose
   } #end of foreach
} #end of if $Previous thumbprint

    # Done validation

    #
    # Do the work
    #
    #

    Write-Verbose -Message "Create CSR" -Verbose
    $csr = New-ICE-CSR -commonName $commonName 
 
    Write-Verbose -Message "Test CSR" -Verbose

    If (Test-ICE-CSR -csrstring  $csr) {
      "CSR Passed"
    }
    else {
       Write-Error "Not A Valid CSR"
    }

    $Comments="Enrolled by PSUniversal, Job " +  $UAJob.Id + ", User " + $UAJob.Identity.Name + "," +  $Comments

    if ($ApplicationName)
    {
      $customFields = @(
        @{
            name  = "ApplicationName"
            value = $ApplicationName 
        }
      )
    }

    Write-Verbose -Message "Setting up params for Enroll-SectigoCertificateRequest" -Verbose

    $splat = @{
      Csr=$csr
      dcvEmail=$RequesterEmail
      Comment=$Comments
      KeyType=$KeyType
      subjAltNames=$SubjectAlternative
    }

    $b1 = @{
      customFields = $customFields
    }

    if ($customFields) {
      $splat = $splat+ $b1
    }

    $cred=$Secret:SectigoClientSecret
    $env:Sectigoclientid = $cred.UserName
    $env:SectigoclientSecret = $cred.GetNetworkCredential().Password

    Write-Verbose -Message "Enroll-SectigoCertificateRequest" -Verbose
    Get-SectigoApiToken 

    $certRequest = Enroll-SectigoCertificateRequest @Splat

    Write-Verbose -Message "Waiting for Cert Status" -Verbose

    while ($certstatus -ne "Issued") {
      $certstatus=(Get-SectigoCertificate -OrderId $certRequest.sslid).status
      Sleep 1
      $run= $run + 1
      if ($run -gt 60) {
        Write-Error "Failed to get issue status after 1 minute..exiting"
        exit
      }
    }

    Write-Verbose -Message "Downloading Certificate" -Verbose

    $CertRootPath="c:\psautocerts\"
    mkdir $CertRootPath 2>$null
    
    $CertPath = (Download-SectigoCertificate -Orderid $certRequest.sslid -Format $Format -CertRootPath $CertRootPath).FullName

    Write-Verbose -Message "Generate Password" -Verbose

    $pfxPassword= Generate-ICE-PFXPassword
    $secure_pfxpassword = ConvertTo-SecureString $pfxPassword -AsPlainText -Force
    $pfxCredential = [System.Management.Automation.PSCredential]::new("None", $secure_pfxpassword)

    Write-Verbose -Verbose "Convert to pfx"

    $results=Convert-ICE-PKS7toPfx -CertFile $CertPath -pfxCredential $pfxCredential
    $pfxPath=$results.Fullname

    Write-Verbose -Verbose "Load the certificate object"

    $collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
    $collection.Import($pfxPath, $pfxPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet)
    # Display all certificates in the chain
    #$collection | Format-List Subject, Issuer, Thumbprint, NotAfter
    $foundCerts = $collection.Find([System.Security.Cryptography.X509Certificates.X509FindType]::FindBySubjectName, $CommonName, $false)
    $ExpiryDate = $foundCerts[0].NotAfter
    $Thumbprint=$foundCerts[0].Thumbprint

    if ($PSCmdlet.ParameterSetName -eq 'Cloud Service') {
       $PfxtoPasswordState=$True
    }
 
    if ($PfxtoPasswordState) {
      Write-Verbose -Verbose "Save to Password State"


        $PasswordStateParams = @{
            Title                  = $FriendlyName;
            Description            = $Comments ;
            ExpiryDate             = $ExpiryDate ;
            APICreds               = $Secret:pwdvault_WindowsCertificates ;
            pfxCredential          = $pfxCredential;
            PfxPath                = $pfxPath;
        }

     $PasswordStateSuccess=Send-ICE-PfxtoPasswordState @PasswordStateParams 
    }

      #Send file to cert store windows only"
      if ($PSCmdlet.ParameterSetName -eq 'Windows') {
       $CertificatetoCertStore = @{
           pfxPath              = $pfxPath;
           RemoteCertPath       = "c:\temp\certificatex.pfx"; 
           DestinationServer    = $DestinationServerArray
           Credential           = $Secret:ndgov_svcitdpsuwin ;
           pfxCredential        = $pfxCredential;
           CertStoreLocation    = "Cert:\LocalMachine\MY";
           ThumbPrint           = $ThumbPrint ;
           FriendlyName         = $FriendlyName
       }

       $CertStoreResults=Send-ICE-CertificatetoCertStore  @CertificatetoCertStore 
       $CertStoreResults
      }

    Write-Verbose -Verbose "Cleaning Up Temp Files"
    if (Test-Path -Path $CertPath  -PathType Leaf) {
        Remove-Item -Path $CertPath -Force -Confirm:$false 2>$null
    }

    if (Test-Path -Path $pfxPath  -PathType Leaf) {
        Remove-Item -Path $pfxPath -Force -Confirm:$false 2>$null
    }

    # Validate the user
    $StartDateTime = (Get-Date)
    $EndDateTime = $StartDateTime.AddMinutes(1)
    $RequestedBy=$UAJob.Identity.Name
    
    if ($PSCmdlet.ParameterSetName -eq 'Cloud Service' -and $PasswordStateSuccess -eq $True ) { $Completed=$true}
    if ($PSCmdlet.ParameterSetName -eq 'Windows' -and $CertStoreResults.Success -eq $True) { $Completed=$true}

    
    if ($Completed) {
        Write-Verbose -Message "Create CHG request for the work" -Verbose
        $ServiceNowEnvironment = "Production" #'Production', 'Test', 'Development'
        New-ITDServiceNowSession -Environment $ServiceNowEnvironment -Credential $Secret:snow_vmcred
        $NewITDServiceNowChangeRequestParams = @{
            TemplateName              = 'NDIT-SPS-PSU Cert Automation Platform'
            RequestedByUsername       = $RequestedBy.split('@')[0] -replace 'prv';
            Category                  = 'Systems Platforms - Systems';
            Subcategory               = 'Windows';
            Impact                    = 3;
            ShortDescription          = "New Certificate Created - PSU Job Id $PSUJobId";
            Description               = "New Certificate Created - PSU Job Id $PSUJobId";
            Justification             = "Security Standards require an updated certificate";
            Implementation            = "PSUniversal execution";
            RiskImpactAnalysis        = "Low";
            BackoutPlan               = "Revoke Cert"
            TestPlan                  = "n/a"
            WhoIsImpacted             = "Windows System Administrators";
            StartTime                 = $StartDateTime
            EndTime                   = $StartDateTime.AddMinutes(1);
            AssignmentGroup           = 'NDIT-Computer Systems Windows';
            ChangeManagerUsername     = 'khellman';
            ChangeCoordinatorUsername = 'gpgolberg';
            AssignedToUsername        = $RequestedBy.split('@')[0] -replace 'prv';
        }

        $CHG = New-ITDServiceNowChangeRequest @NewITDServiceNowChangeRequestParams -Verbose
        $CHGNum = $CHG.Number.value

        Write-Verbose -Message ("Completing Snow " + $CHG.Number.value) -Verbose
        $CompleteITDServiceNowChangeRequestParams = @{
            Number     = $CHG.Number.value
            CloseCode  = "Successful"
            CloseNotes = ("New Certificate" + $obj.ADDomain + "\" + $obj.SamAccountName + " created.")
        }
        Complete-ITDServiceNowChangeRequest @CompleteITDServiceNowChangeRequestParams -Verbose

        Write-Verbose -Message "Status Success" -Verbose
        $Jobstatus = "Success"
    
    }
    Else {
        Write-Verbose -Message "Status Failure" -Verbose
        $JobStatus = "Failure"

    }

Send-ICE-Mail -recipientsString $RequesterEmail  -Jobid $PSUJobId  -status $Jobstatus -Message "Created Standard Change"



$log_psobject=[pscustomobject]@{
    Timestamp           = (Get-Date)
    ParameterSetName    = $ParameterSetName
    RequestedBy         = $RequestedBy
    RequesterEmail      = $RequesterEmail
    CommonName          = $CommonName 
    SubjectAlternative  = $SubjectAlternative
    DestinationServer   = $DestinationServer
    PfxtoPasswordState  = $PfxtoPasswordState
    ApplicationName     = $ApplicationName  
    ExpiryDate          = $ExpiryDate
    Thumbprint          = $Thumbprint  
    PreviousThumbprint  = $PreviousThumbprint
    is_retired          = $false
 } 

 Write-Verbose -Verbose "Log new transaction to both tables. "
#Cache table common name is the primary key so there should only be an update?

 $table=@("certlog","certcache")
 Foreach ($t in $table) {
    $log_psobject| Add-JDJson -TableName $t -Verbose
 }






    ###########################################
    if ($PasswordStateSuccess) {
       "Your new Certificate is in PasswordState at: "
       "   Windows/Certificates/${FriendlyName}"
    }
}