ACMEDNS01Certificate.psm1
<#
.SYNOPSIS Generate SSL Certificates .DESCRIPTION The script will generate SSL Certificates using ACMESharp's DNS-01 .EXAMPLE New-ACMEDNS01Certificate -Name hostname -ZoneName domain.tld -DnsMasterServer 127.0.0.1 -DnsValidationServer 8.8.8.8 -Staging -CertificateExport New-ACMEDNS01Certificate for hostname.domain.tld, using 172.0.0.1 as the DNS server and 8.8.8.8 to validate DNS replication. .NOTES .LINK https://github.com/EddyBeaupre/ACMEDNS01Certificate #> function New-ACMEDNS01Certificate { param ( # DNS record name. [Parameter(Mandatory=$true)][string]$Name, # DNS record zone. [Parameter(Mandatory=$true)][string]$ZoneName, # Initialize ACMEVault. [Parameter(Mandatory=$false)][switch]$Initialize = $false, # Use the Staging servers (For tests). [Parameter(Mandatory=$false)][switch]$Staging = $false, # Force Initialize ACMEVault. [Parameter(Mandatory=$false)][switch]$Force = $false, # Contact information, [Parameter(Mandatory=$false)][string]$ContactEmail = "", # Master DNS Server, [Parameter(Mandatory=$false)][string]$DnsMasterServer = "127.0.0.1", # Name server for DNS Validation, [Parameter(Mandatory=$false)][string]$DnsValidationServer = "127.0.0.1", # Export Certificates. [Parameter(Mandatory=$false)][switch]$CertificateExport, # OutPath for Certificates. [Parameter(Mandatory=$false)][string]$CertificatePath, # Force overwrite of certificates. [Parameter(Mandatory=$false)][switch]$CertificateOverwrite = $false, # Silent. [Parameter(Mandatory=$false)][switch]$Silent = $false ) Import-Module DnsServer Import-Module ACMESharp filter TimeStamp {"$(Get-Date -UFormat "%Y/%m/%d-%H:%m:%S"): $_"} function GetTimeStamp { param( # NoNewline. [Parameter(Mandatory=$false)][switch]$Numeric = $false ) if($Numeric) { return Get-Date -UFormat "%Y%m%d%H%m%S" } else { return Get-Date -UFormat "%Y/%m/%d-%H:%m:%S" } } function WriteLog { param( # Message. [Parameter(Mandatory=$False, Position=1)][string]$Message = " ", # Color. [Parameter(Mandatory=$false)][string]$Color = "White", # NoNewline. [Parameter(Mandatory=$false)][switch]$NoNewline = $false, # TimeStamp. [Parameter(Mandatory=$False)][switch]$TimeStamp = $False ) if(!$Silent) { if($TimeStamp) { Write-Host "$(GetTimeStamp): " -ForegroundColor DarkGreen -NoNewline } Write-Host "$Message" -ForegroundColor $Color -NoNewline:$NoNewline } } function Main-ACMECertificate { WriteLog "ACMEVault " -NoNewline $ACMEVault = Get-ACMEVault if ((!$ACMEVault) -or $Initialize) { try { WriteLog "(" -NoNewline if($Initialize) { WriteLog "Forced, " -NoNewLine -Color Cyan } $BaseService = "LetsEncrypt" if($Staging) { $BaseService = "LetsEncrypt-STAGING" } WriteLog "Base Service " -NoNewLine WriteLog "$BaseService" -NoNewLine -Color Cyan WriteLog ") : " -NoNewLine Initialize-ACMEVault -Force:$Initialize -BaseService $BaseService WriteLog "initialized." -Color Green $ACMEVault = Get-ACMEVault } catch { WriteLog "failed initialization" -Color Red Exit } } else { WriteLog "(Base Service " -NoNewLine WriteLog "$($ACMEVault.BaseService)" -NoNewline -Color Cyan WriteLog ") : " -NoNewLine WriteLog "Available." -Color Green } if([string]::IsNullOrWhiteSpace($ACMEVault.Registrations)) { try { if([string]::IsNullOrWhiteSpace($ContactEmail) -or !(ValidEmailAddress "$ContactEmail")) { $ContactEmail = Read-Host "Please provide a valid contact email address" } WriteLog "Registering contact " -NoNewline WriteLog "$ContactEmail" -NoNewline -Color Cyan WriteLog " : " -NoNewline $ACMERegistration = New-ACMERegistration -Contacts "mailto:$ContactEmail" -AcceptTos WriteLog "success." -Color Green } catch { WriteLog "fail." -Color Red Exit } } ExportAcmeCertificate $(ValidateAcmeCertificate $(ValidateAcmeIdentifier)) } function FindAcmeIdentifier { param( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Dns ) WriteLog "Searching existing ACME identifier for " -NoNewline WriteLog "$Dns" -Color Cyan -NoNewline WriteLog " : " -NoNewline forEach($identifier in $(Get-ACMEIdentifier)) { if(!$($identifier.Status -eq "invalid")) { if($identifier.Dns -eq "$Dns") { WriteLog "$($identifier.Alias)." -Color Green return $identifier } } } WriteLog "None." -Color DarkGreen WriteLog "Creating new ACME identifier for " -NoNewline WriteLog "$Dns" -Color Cyan -NoNewline WriteLog " : " -NoNewline $identifier = New-ACMEIdentifier -Dns $Dns -Alias "$($Dns.replace('.','-'))-$(GetTimeStamp -Numeric)" forEach($identifier in $(Get-ACMEIdentifier)) { if(!$($identifier.Status -eq "invalid")) { if($identifier.Dns -eq "$Dns") { WriteLog "$($identifier.Alias)." -Color Green return $identifier } } } else { WriteLog "Error" -Color Red Exit } } function ValidateAcmeIdentifier { WriteLog $ACMEIdentifier = $(FindAcmeIdentifier "$Name.$ZoneName") if($($ACMEIdentifier.Status) -eq "valid") { return $ACMEIdentifier } else { WriteLog "ACME Identifier : " -NoNewline WriteLog "$($ACMEIdentifier.Alias)." -Color Cyan -NoNewline WriteLog " state : " -NoNewline WriteLog "$($ACMEIdentifier.Status)." -Color Green WriteLog "Complete ACMEChallenge for " -NoNewline WriteLog "$($ACMEIdentifier.Alias)" -Color Cyan -NoNewline WriteLog " state : " -NoNewline $ResponseFile = [System.IO.Path]::GetTempFileName() Remove-Item -Path "$ResponseFile" $AcmeChallenge = Complete-ACMEChallenge -IdentifierRef "$($ACMEIdentifier.Alias)" -ChallengeType dns-01 -Handler manual -HandlerParameters @{"WriteOutPath" = "$ResponseFile"; "OutputJson" = $true} if($AcmeChallenge.Status -eq "pending") { WriteLog "$($AcmeChallenge.Status)." -Color Green } else { WriteLog "$($AcmeChallenge.Status)" -Color Red Exit } if(!$(Test-Path "$ResponseFile")) { WriteLog "Response file not found." -Color Red Exit } $ResponseData = (Get-Content "$ResponseFile") | ConvertFrom-Json Remove-Item -Path "$ResponseFile" $RecordName = $ResponseData.DnsDetails.RRName.Replace(".$ZoneName", "") $RecordData = $ResponseData.DnsDetails.RRValue if(!(CreateDnsTxtRecord "$RecordName" "$ZoneName" "$RecordData" $DnsMasterServer)) { Exit } WaitForTxtReplication "$RecordName" "$ZoneName" "$RecordData" $DnsValidationServer -Sleep 30 $SubmitACMEChallenge = Submit-ACMEChallenge -IdentifierRef $ACMEIdentifier.Alias -ChallengeType dns-01 WaitForACMEIdentifier $ACMEIdentifier.Alias -Sleep 10 return $(FindAcmeIdentifier $Dns) } } function FindAcmeCertificate { param( # IdentifierRef. [Parameter(Mandatory=$true, Position=1)][string]$IdentifierRef ) WriteLog "Searching existing ACME certificate for " -NoNewline WriteLog "$IdentifierRef" -Color Cyan -NoNewline WriteLog " : " -NoNewline $certificate = $(Get-ACMECertificate -CertificateRef "$IdentifierRef-cert") 2> $null if(!$($certificate -eq $null)) { WriteLog "$($certificate.Alias)." -Color Green return $certificate } WriteLog "Not found." -Color Green WriteLog "Creating a new certificate for " -NoNewline WriteLog "$IdentifierRef-cert" -Color Cyan -NoNewline WriteLog " : " -NoNewline $certificate = New-ACMECertificate -Generate -IdentifierRef $IdentifierRef -AlternativeIdentifierRefs @("$IdentifierRef") -Alias "$IdentifierRef-cert" $certificate = $(Get-ACMECertificate -CertificateRef "$IdentifierRef-cert") 2> $null if(!$($certificate -eq $null)) { WriteLog "Success." -Color Green return $certificate } WriteLog "Error" -Color Red Exit } function ValidateAcmeCertificate { param( # ACMEIdentifier. [Parameter(Mandatory=$true, Position=1)][object]$ACMEIdentifier ) WriteLog if($ACMEIdentifier.Status -eq "valid") { WriteLog "ACME Identifier : " -NoNewline WriteLog "$($ACMEIdentifier.Alias)." -Color Cyan -NoNewline WriteLog " state : " -NoNewline WriteLog "$($ACMEIdentifier.Status)." -Color Green $ACMECertificate = FindAcmeCertificate "$($ACMEIdentifier.Alias)" if([string]::IsNullOrWhiteSpace($ACMECertificate.IssuerSerialNumber)) { WriteLog "Submitting certificate request for : " -NoNewline WriteLog "$($ACMECertificate.Alias)" -Color Cyan -NoNewline WriteLog " : " -NoNewline $ACMECertificate = Submit-ACMECertificate -CertificateRef "$($ACMECertificate.Alias)" WriteLog "Done." -Color Green $ACMECertificate = WaitForACMECertificate -CertificateRef "$($ACMECertificate.Alias)" -Sleep 10 } WriteLog "Fetching signed certificates : " -NoNewline WriteLog "$($ACMECertificate.Alias)" -Color Cyan -NoNewline WriteLog " : " -NoNewline $ACMECertificate = Get-ACMECertificate -CertificateRef "$($ACMECertificate.Alias)" WriteLog "Done." -Color Green return $ACMECertificate } else { WriteLog "ACME Identifier : " -NoNewline WriteLog "$ACMEIdentifier.Alias." -Color Cyan -NoNewline WriteLog " state : " -NoNewline WriteLog "$($ACMEIdentifier.Status)" -Color Red return $null } } function ShowFileDetail { param( # File. [Parameter(Mandatory=$true, Position=1)][string]$File = "", # Path. [Parameter(Mandatory=$true, Position=2)][string]$Path = "", # FilePath. [Parameter(Mandatory=$true, Position=3)][string]$Description = "", # FilePath. [Parameter(Mandatory=$true, Position=4)][string]$Type = "" ) $Data = Get-FileHash "$(Join-Path $Path $File)" WriteLog "$Description (" -NoNewline WriteLog "$Type" -Color Cyan -NoNewline WriteLog ") : " -NoNewLine WriteLog "$($Data.Path)" -Color Green WriteLog "$Description checksum (" -NoNewline WriteLog "$($Data.Algorithm)" -Color Cyan -NoNewline WriteLog ") : " -NoNewLine WriteLog "$($Data.Hash)" -Color Green } function ExportAcmeCertificate { param( # ACMEIdentifier. [Parameter(Mandatory=$true, Position=1)][object]$ACMECertificate ) if($ACMECertificate -and $CertificateExport) { WriteLog WriteLog "Certificate Path : " -NoNewline if([string]::IsNullOrWhiteSpace($CertificatePath)) { $ACMEVaultProfile = $(Get-ACMEVaultProfile) $CertificatePath = Join-Path "$($ACMEVaultProfile.VaultParameters.RootPath)" "certificates" if(!$(Test-Path $CertificatePath)) { New-Item "$CertificatePath" -type directory 2>&1 > $null } WriteLog "$CertificatePath." -Color Green } else { if(!(Test-Path $CertificatePath)) { WriteLog "Path " -Color Cyan -NoNewline WriteLog "$CertificatePath" -Color Red -NoNewline WriteLog " does not exists. Aborting." -Color Cyan Exit } } $ACMECertificate = Get-ACMECertificate -CertificateRef "$($ACMECertificate.Alias)" -ExportKeyPEM $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-key.pem") -ExportCsrPEM $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-csr.pem") -ExportCertificatePEM $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias).pem") -ExportCertificateDER $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias).der") -ExportIssuerPEM $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-issuer.pem") -ExportIssuerDER $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-issuer.der") -ExportPkcs12 $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias).pkcs12") -Overwrite Get-Content $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-key.pem") | Out-File $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-combined.pem") Get-Content $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias).pem") | Out-File -Append $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-combined.pem") Get-Content $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-issuer.pem") | Out-File -Append $(Join-Path "$CertificatePath" "$($ACMECertificate.Alias)-combined.pem") ShowFileDetail "$($ACMECertificate.Alias)-issuer.pem" "$CertificatePath" "CA's intermediary certificate" "PEM encoded" ShowFileDetail "$($ACMECertificate.Alias)-issuer.der" "$CertificatePath" "CA's intermediary certificate" "DER encoded" ShowFileDetail "$($ACMECertificate.Alias)-csr.pem" "$CertificatePath" "Certificate Signing Reques" "PEM encoded" ShowFileDetail "$($ACMECertificate.Alias).pem" "$CertificatePath" "Certificate" "PEM encoded" ShowFileDetail "$($ACMECertificate.Alias).der" "$CertificatePath" "Certificate" "DER encoded" ShowFileDetail "$($ACMECertificate.Alias)-combined.pem" "$CertificatePath" "Combined Key, Certificate and CA's intermediary certificate" "PEM encoded" ShowFileDetail "$($ACMECertificate.Alias).pkcs12" "$CertificatePath" "Certificate" "PKCS#12 encoded" ShowFileDetail "$($ACMECertificate.Alias)-key.pem" "$CertificatePath" "Certificate Key" "PEM encoded" } } function ValidEmailAddress { param ( # EmailAddress. [Parameter(Mandatory=$true, Position=1)][string]$EmailAddress ) WriteLog "Validating email address " -NoNewline WriteLog "$EmailAddress" -Color Cyan -NoNewline WriteLog " : " -NoNewline if ([string]::IsNullOrWhiteSpace($EmailAddress)) { WriteLog "invalid." -Color Red return $false } $Domain = $EmailAddress.Split('@') if(!($Domain.Count -eq 2) -or ([string]::IsNullOrWhiteSpace($Domain[1]))) { WriteLog "invalid." -Color Red return $false } if(!(DnsRecordExists $Domain[1] Mx -Silent)) { WriteLog "invalid." -Color Red return $false } Try { New-Object System.Net.Mail.MailAddress($EmailAddress) 2>&1 > $null } Catch { WriteLog "invalid." -Color Red return $false } WriteLog "valid." -Color Green return $true } function DnsZoneExists { param( # Zone [Parameter(Mandatory=$true, Position=1)][string]$Zone ) try { WriteLog "Searching for zone " -NoNewline WriteLog "$Zone" -NoNewline -Color Cyan WriteLog " : " -NoNewline if(Get-DnsServerZone -Name "$Zone" -ErrorAction SilentlyContinue) { WriteLog "Found." -Color Green return $true } else { WriteLog "Not found." -Color DarkGreen return $false } } catch { WriteLog "Error" -Color Red return $False } } function DnsRecordExists { param( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Name, # Type [Parameter(Mandatory=$true, Position=2)][string]$Type, # Type [Parameter(Mandatory=$False, Position=3)][string]$Server ) try { WriteLog "Searching for dns record " -NoNewline WriteLog "$Name" -NoNewline -Color Cyan WriteLog " of type " -NoNewline WriteLog "$type" -NoNewLine -Color Cyan if(!([string]::IsNullOrWhiteSpace($Server))) { WriteLog " in server " -NoNewline WriteLog "$Server" -NoNewline -Color Cyan } WriteLog " : " -NoNewline if([string]::IsNullOrWhiteSpace($Server)) { $Data = Resolve-DnsName -Name "$Name" -Type $Type -DnsOnly -ErrorAction SilentlyContinue } else { $Data = Resolve-DnsName -Name "$Name" -Type $Type -DnsOnly -Server $Server -ErrorAction SilentlyContinue } if($Data) { forEach($Record in $Data) { if($Record.Type -eq $Type) { WriteLog "Found." -Color Green return $true } } WriteLog "Not found." -Color DarkGreen return $false } WriteLog "Error" -Color Red Exit } catch { WriteLog "Error" -Color Red return $False } } function GetDnsTxtRecord { param( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Name, # Zone [Parameter(Mandatory=$true, Position=2)][string]$Zone, # Type [Parameter(Mandatory=$False, Position=4)][string]$Server = "127.0.0.1" ) try { if(DnsZoneExists "$Zone" ) { WriteLog "Fetching dns record " -NoNewline WriteLog "$Name.$Zone" -NoNewline -Color Cyan WriteLog " of type " -NoNewline WriteLog "TXT" -NoNewLine -Color Cyan WriteLog " in server " -NoNewline WriteLog "$Server" -NoNewline -Color Cyan WriteLog " : " -NoNewline $Values = New-Object System.Collections.ArrayList $Data = Resolve-DnsName -Name "$Name.$Zone" -Type TXT -DnsOnly -Server $Server -ErrorAction SilentlyContinue if($Data) { forEach($Record in $Data) { if($Record.Type -eq "TXT") { $Values.Add($Record.Strings) 2>&1 > $null } } } WriteLog "$($Values.Count)." -NoNewline -Color Green WriteLog " records found" return $Values } Exit } catch { WriteLog "Error" -Color Red return $null } } function RemoveDnsRecord { param( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Name, # Zone [Parameter(Mandatory=$true, Position=2)][string]$Zone, # Type [Parameter(Mandatory=$true, Position=3)][string]$Type, # Server [Parameter(Mandatory=$false, Position=4)][string]$Server = "127.0.0.1" ) try { if(DnsZoneExists "$Zone") { if(DnsRecordExists "$Name.$Zone" "$Type" "$Server") { WriteLog "Removing DNS Record " -NoNewline WriteLog "$Name.$Zone" -NoNewline -Color Cyan WriteLog " of type " -NoNewline WriteLog "$type" -NoNewLine -Color Cyan WriteLog " in server " -NoNewline WriteLog "$server" -NoNewline -Color Cyan WriteLog " : " -NoNewline Remove-DnsServerResourceRecord -ComputerName $Server -Name $Name -ZoneName $Zone -RRType $Type -Force -ErrorAction Stop WriteLog "Ok." -Color Green return $true } } return $false } catch { WriteLog "Error" -Color Red return $false } } function CreateDnsTxtRecord { param( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Name, # Zone [Parameter(Mandatory=$true, Position=2)][string]$Zone, # Data [Parameter(Mandatory=$true, Position=3)][string]$Data, # Server [Parameter(Mandatory=$false, Position=4)][string]$Server = "127.0.0.1" ) try { if(RemoveDnsRecord $Name $Zone TXT $Server) { WriteLog "Creating Txt DNS Record " -NoNewline WriteLog "$Name.$Zone" -NoNewline -Color Cyan WriteLog " with data " -NoNewline WriteLog $Data -NoNewLine -Color Cyan WriteLog " in server " -NoNewline WriteLog "$server" -NoNewline -Color Cyan WriteLog " : " -NoNewline Add-DnsServerResourceRecord -ComputerName $Server -Txt -Name $Name -ZoneName $Zone -DescriptiveText "$Data" WriteLog "Ok." -Color Green } return $true } catch { WriteLog "Error" -Color Red return $false } } function WaitForTxtReplication { param ( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$Name, # Zone [Parameter(Mandatory=$true, Position=2)][string]$Zone, # Data [Parameter(Mandatory=$true, Position=3)][string]$Data, # Server [Parameter(Mandatory=$false, Position=4)][string]$Server = "127.0.0.1", # Server [Parameter(Mandatory=$false)][int]$Sleep = 10 ) $StartTime = $(Get-Date) WriteLog "Waiting for DNS Replication of " -NoNewline WriteLog "TXT" -NoNewline -Color Cyan WriteLog " record " -NoNewline WriteLog "$Name.$Zone" -NoNewline -Color Cyan WriteLog " on server " -NoNewline WriteLog "$Server" -NoNewline -Color Cyan WriteLog " : " -NoNewline $Sleep = ($Sleep * 1000) Do { forEach($Value in GetDnsTxtRecord "$Name" "$Zone" $Server -Silent) { if($Value -eq $Data) { WriteLog "Ok." -Color Green -NoNewline $TimeSpan = New-TimeSpan $StartTime $(Get-Date) WriteLog " Replication took " -NoNewline WriteLog "$([math]::Truncate($TimeSpan.TotalSeconds))" -NoNewline -Color Cyan WriteLog " seconds." return } } for($i = 0; $i -lt 100; $i++) { $TimeSpan = New-TimeSpan $StartTime $(Get-Date) Write-Progress -Id 1 -Activity "Waiting for DNS Replication" -Status "$([math]::Truncate($TimeSpan.TotalSeconds)) seconds elapsed. Next check in $([math]::Truncate(($Sleep - ($i * ($Sleep / 100))) / 1000)) seconds..." -PercentComplete $i Start-Sleep -Milliseconds $($Sleep / 100) } } While($true) } function WaitForACMEIdentifier { param ( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$IdentifierRef, # Sleep [Parameter(Mandatory=$false)][int]$Sleep = 10 ) $StartTime = $(Get-Date) WriteLog "Waiting for ACMEIdentifier update of " -NoNewline WriteLog "$IdentifierRef" -NoNewline -Color Cyan WriteLog " : " -NoNewline $Sleep = ($Sleep * 1000) Do { $ACMEIdentifier = Update-ACMEIdentifier -IdentifierRef $IdentifierRef if($ACMEIdentifier.Status -eq "valid") { WriteLog "Ok." -Color Green -NoNewline $TimeSpan = New-TimeSpan $StartTime $(Get-Date) WriteLog " Update took " -NoNewline WriteLog "$([math]::Truncate($TimeSpan.TotalSeconds))" -NoNewline -Color Cyan WriteLog " seconds." return; } if($ACMEIdentifier.Status -eq "invalid") { WriteLog "invalid" -Color Red -NoNewline $TimeSpan = New-TimeSpan $StartTime $(Get-Date) WriteLog " Update took " -NoNewline WriteLog "$([math]::Truncate($TimeSpan.TotalSeconds))" -NoNewline -Color Cyan WriteLog " seconds." Exit; } for($i = 0; $i -lt 100; $i++) { $TimeSpan = New-TimeSpan $StartTime $(Get-Date) Write-Progress -Id 1 -Activity "Waiting for ACMEIdentifier update" -Status "$([math]::Truncate($TimeSpan.TotalSeconds)) seconds elapsed. Next check in $([math]::Truncate(($Sleep - ($i * ($Sleep / 100))) / 1000)) seconds..." -PercentComplete $i Start-Sleep -Milliseconds $($Sleep / 100) } } While($true) } function WaitForACMECertificate { param ( # Dns. [Parameter(Mandatory=$true, Position=1)][string]$CertificateRef, # Sleep [Parameter(Mandatory=$false)][int]$Sleep = 10 ) $StartTime = $(Get-Date) WriteLog "Waiting for ACMECertificate update of " -NoNewline WriteLog "$CertificateRef" -NoNewline -Color Cyan WriteLog " : " -NoNewline $Sleep = ($Sleep * 1000) Do { $ACMECertificate = Update-ACMECertificate -CertificateRef $CertificateRef if(![string]::IsNullOrWhiteSpace($ACMECertificate.IssuerSerialNumber)) { WriteLog "Ok." -Color Green -NoNewline $TimeSpan = New-TimeSpan $StartTime $(Get-Date) WriteLog " Update took " -NoNewline WriteLog "$([math]::Truncate($TimeSpan.TotalSeconds))" -NoNewline -Color Cyan WriteLog " seconds." return $ACMECertificate; } for($i = 0; $i -lt 100; $i++) { $TimeSpan = New-TimeSpan $StartTime $(Get-Date) Write-Progress -Id 1 -Activity "Waiting for ACMECertificate update" -Status "$([math]::Truncate($TimeSpan.TotalSeconds)) seconds elapsed. Next check in $([math]::Truncate(($Sleep - ($i * ($Sleep / 100))) / 1000)) seconds..." -PercentComplete $i Start-Sleep -Milliseconds $($Sleep / 100) } } While($true) } Main-ACMECertificate } |