vSphereAutoLab/Build/Automate/VC/Derek-SSL.ps1

1060 lines
37 KiB
PowerShell

# Creates vCenter 5.5 certificates and related files
# Do not use with vCenter 5.1. Run on the vCenter 5.5 server.
#
# Derek Seaman, VCDX #125, www.derekseaman.com
# vSphere 5.5 Install series: vexpert.me/Derek55
# For full instructions see Part 8 & 9 in the vSphere 5.5 install series
# Download the latest version from: vexpert.me/toolkit55
#
# v1.59 August 9, 2014
# Updated OpenSSL download to 0.9.8.zb
# Added check for PowerShell 3.0 (minimum requirement)
#
# v1.58 July 12, 2014
# Updated OpenSSL download to 0.9.8za
# Removed SQL 2012 SP1 client download (link broken)
# Fixed Database creation script bug
# Added additional error handling and Powershell-ized more commands
# Changed the sts.properties file to use sts in the URI per KB2058519
#
# v1.57 February 14, 2014
# More robust handling of non-internet connected systems
# Removed line continuation characters
#
# v1.56 January 19, 2014
# Fixed bug when no subordinate CA was present (Thanks Troy)
# Changed Microsoft "renewal" default to 0 for root/subordinate
#
# v1.55 January 12, 2014
# Added additional CA/subordinate error checking
#
# v1.50 December 22, 2013
# Added ESXi host support
#
# v1.42 December 3, 2013
# Modified how the certificate hash files are created
# Added Authentication Proxy certificate generation
# Changed MS CA download parameter to Renewal=1
#
# v1.41 November 14, 2013
# Changed the root/intermediate CA download order and added more error checking
#
# v1.40 November 10, 2013
# Added Auto Deploy, Dump Collector and Syslog collector SSL certs for Windows
# Added support for CA approval of submitted requests (Thanks Ryan Bolger)
# Added SHA512 request in CSR creation
# Ask for vCenter name when selecting Option 3
#
# v1.31 Octover 29, 2013
# Bugfix in option #2 where CSRs would fail to create
#
# v1.3 October 22, 2013
# Added basic support for vCenter Server Appliance cert minting/CSR
# Added support for manually entering vCenter FQDN
# Changed method of building the automatic vCenter FQDN
#
# v1.2 October 19, 2013
# Added SQL database script creation
# Added vCenter/VUM DSN creation
#
# v1.1 October 10, 2013 Changes:
# Added IP address support for SAN field
# Added configurable CA download method (HTTP or HTTPS)
# Skips Root/subordinate certificate download if files already exist
#
#
[CmdletBinding()]
param()
# Directory where the certificate folders will be created. Does not need to exist.
$Cert_Dir = "C:\Certs"
# Path to your existing Open SSL directory. It may be c:\OpenSSL-Win32, too
# If OpenSSL is not located in this directory it will be downloaded and installed
$openssldir = "C:\OpenSSL"
# Modify these Certificate Details for your environment
$Country="NZ"
$State="BoP"
$City="Tauranga"
$org="AutoLab"
# If you want the vCenter server IP address included in the certificate set
# the value to the appropriate IP. If you don't want an IP, comment out the line.
# This applies to Windows vCenter and the vCenter Appliance.
$vCenterIP="192.168.199.5"
# The URLs where your Root and Subordinate CA certificates can be downloaded.
# If your CA certificates are not available online or you don't have a subordinate
# CA, just comment out the associated lines with a hash.
#
# If you have an online Microsoft CA running the Web Enrollment role service,
# the CA certificate should be downloadable using the following URL:
# http(s)://YourCA.domain/certsrv/certnew.cer?ReqID=CACert&Renewal=0&Enc=b64
#
# If your have issues with the root certificate downloading, change Renewal=0
# in the body of the code. Or if the tool is downloading an expired certificate,
# increase the renewal number until it pulls the current certificate.
#
# If you CA doesn't have web services or enabled or it's offline, you can download
# the root and intermediate CA certs manually and place them in the $Cert_Dir.
# Please see Part 9 of my vexpert.me\Derek55 series for details on how to create
# the root/intermediate files in the proper format.
#
$rootCA = "dc.lab.local"
#$SubCA = "subca01.contoso.local"
# If your CA web enrollment site is not SSL enabled change to HTTP (insecure)
# Ignore if you don't have online Microsoft CAs.
$CADownload = "http"
# Online Microsoft CA name that will issue the certificates.
# Ignore if you don't have online Microsoft CAs.
$ISSUING_CA = "dc\LabCA"
# Your VMware CA certificate template name (not the display name; no spaces)
# Ignore if you don't have online Microsoft CAs.
$Template = "CertificateTemplate:VMware-SSL"
#######
# The magic happens here...don't modify
#######
# SSO and vCenter administrator usernames. Should not need to change these.
$sso_admin = "administrator@vsphere.local"
$vc_admin = "administrator@vsphere.local"
$rootcer = "$Cert_Dir\root64.cer"
$intermcer = "$Cert_Dir\interm64.cer"
$openssl = $openssldir+"\bin\openssl.exe"
$ESXUser = "root"
$wc = New-Object System.Net.WebClient
$wc.UseDefaultCredentials = $true
New-Alias -Name OpenSSL $openssl
$Script:CertsWaitingForApproval = $false
$WServices = @("vCenterServer","vCenterInventoryService","vCenterSSO","VMwareUpdateManager","vCenterWebClient","vCenterLogBrowser","VMwareOrchestrator","AutoDeploy","DumpCollector","SysLogCollector", "AuthenticationProxy")
$LServices = @("VMware vCenter Service Certificate","VMware Inventory Service Certificate","VMware LDAP Service Certificate","VMware vCenter VAMI Certificate","vCenter Web Client Service Certificate","VMware Logbrowser Service Certificate","VMware vSphere Autodeploy Service Certificate")
# Check for PowerShell 3.0 and higher (required)
$PSpath = "HKLM:\SOFTWARE\Microsoft\PowerShell\3"
if(!(Test-Path $PSpath)) {
write-host "PowerShell 3.0 or higher required. Please install"; exit
}
# Download OpenSSL if it's not already installed
if (!(Test-Path($openssl))) {
Write-Host -Foreground "DarkBlue" -Background "White" "Downloading OpenSSL.."
$null = New-Item -Type Directory $openssldir -erroraction silentlycontinue
$sslurl = "http://slproweb.com/download/Win32OpenSSL-0_9_8zb.exe"
$sslexe = "$env:temp\openssl.exe"
$wc.DownloadFile($sslurl,$sslexe)
$env:path = $env:path + ";$openssldir"
if (!(test-Path($sslexe))) { write-host -Foreground "red" -Background "white" "Could not download or find OpenSSL. Please install OpenSSL 0.9.8y manually."; exit}
Write-Host -Foreground "DarkBlue" -Background "White" "Installing OpenSSL.."
cmd /c $sslexe /silent /verysilent /sp- /suppressmsgboxes
Remove-Item $sslexe
}
# Create certificate directory if it does not exist
if(!(Test-Path $Cert_Dir)) { New-Item $Cert_Dir -Type Directory }
#
# Functions Begin Here
#
Function CheckOpenSSL {
if (!(Test-Path $openssl)) {throw "Openssl required, unable to download, please install."}
}
Function WinVCCheck {
# Validates Windows vCenter SSO is installed
# Sets SSO filesystem path if SSO is installed
$ssoregpath = "HKLM:\SOFTWARE\VMware, Inc.\VMware Identity Services"
if(!(Test-Path $ssoregpath)) {
write-host "SSO 5.5 not installed. Please install it first."; exit
}
Else {
$ssoreg = (Get-ItemProperty -Path $ssoregpath)
$Script:ssodir = $ssoreg.InstallPath ; $ssodir= $ssodir -replace ".$"
}
# Configures JRE keytool alias with path if SSO is installed
$JREregpath = "HKLM:\SOFTWARE\VMware, Inc.\VMware Infrastructure\vJRE"
if(!(Test-Path $JREregpath)) {
write-host "JRE not installed. Please install SSO 5.5 first."; exit
}
Else {
$JREreg = (Get-ItemProperty -Path $JREregpath)
$JREBinDir = $JREreg.InstallPath ; $JREBinDir= $JREBinDir -replace ".$"
$keytool = $JREBinDir+"\bin\keytool.exe"
New-Alias -Name keytool $keytool -Scope script
}
}
Function VCFQDN {
# Construct vCenter server hostname (localhost) and ask for input
$Computername = get-wmiobject win32_computersystem
$DEFFQDN = "$($computername.name).$($computername.domain)".ToLower()
$Script:FQDN = $(
Write-Host "Is the vCenter FQDN $DEFFQDN ?"
$Input = Read-Host "Press ENTER to accept or input a new vCenter FQDN"
If ($input) {$input} else {$DEFFQDN}
)
$POS = $FQDN.IndexOf(".")
$Script:Shortname = $FQDN.Substring(0, $POS)
}
Function DownloadRoot
{
# Download Root CA public certificate, if defined
# If the certificate exists (root64.cer) then it won't attempt to download
if ($RootCA) {
If (!(test-path -Path $rootcer)){
write-host "Downloading root certificate from $rootca ..."
$url = "$CADownload"+"://$rootCA/certsrv/certnew.cer?ReqID=CACert&Renewal=0&Enc=b64"
$wc.DownloadFile($url,$rootcer)
If (!(test-path -Path $rootcer)) {write-host "Root64.cer did not download. Check Root CA variable, CA web services, or manually download root cert and copy to $Cert_Dir\root64.cer. See vExpert.me/Derek55 Part 9 for more details." -foregroundcolor red;exit}
Write-host "Root CA download successful." -foregroundcolor yellow
}
Else { Write-host "Root CA file found, will not download." -ForegroundColor yellow}
}
$Validation = select-string -simple CERTIFICATE----- $rootcer
If (!$Validation) {write-host "Invalid Root certificate format. Validate BASE64 encoding and try again." -foregroundcolor red; exit}
}
Function DownloadSub
{
# Download Subordinate CA public certificate, if defined
# If the certificate exists (interm64.cer) then it won't attempt to download
if ($SubCA) {
If (!(test-path -Path $intermcer)){
write-host "Downloading subordinate certificate from $subca ..."
$url = "$CADownload"+"://$SubCA/certsrv/certnew.cer?ReqID=CACert&Renewal=1&Enc=b64"
$wc.DownloadFile($url,$intermcer)
If (!(test-path -Path $intermcer)) {write-host "Interm64.cer did not download. Check Intermediate CA variable, CA web services, or manually download intermediate cert and copy to $Cert_Dir\interm64.cer. See vExpert.me/Derek55 Part 9 for more details." -foregroundcolor red;exit}
Write-host "Intermediate CA download successful." -foregroundcolor yellow
}
Else { Write-host "Intermediate CA file found, will not download." -ForegroundColor yellow}
$Validation = select-string -simple CERTIFICATE----- $intermcer
If (!$Validation) {write-host "Invalid subordinate certificate format. Validate BASE64 encoding and try again." -foregroundcolor red; exit}
}
}
Function CAHashes{
# Computes CA hash file(s)
# Skip if we have pending cert requests
if ($Script:CertsWaitingForApproval) { return }
# Prompt for Root cert if it's not there yet
While (!(Test-Path $rootcer)) {
read-host "Please copy the Root CA certificate root64.cer (Base64 encoded) to $rootcer and press Enter to continue"
}
$roothash = & OpenSSL x509 -subject_hash -noout -in $rootcer
$hashdest = $roothash + '.0'
copy-item -path $rootcer -Destination $Cert_Dir\$hashdest
If (Test-Path $intermcer) {
$intermhash = & OpenSSL x509 -subject_hash -noout -in $intermcer
$interdest = $intermhash + '.0'
Copy-Item -Path $intermcer -Destination $Cert_Dir\$interdest
cmd /c copy $intermcer+$rootcer $Cert_Dir\chain.cer
}
write-host "Root CA hash is $roothash" -foregroundcolor yellow
If ($intermhash) { write-host "Intermediate CA hash is $intermhash" -foregroundcolor yellow }
}
Function CreateCSR {
# Create RSA private keys and CSRs
# If IP address is defined, add it to the SAN field
If ($vCenterIP) { $IP = " IP:$vCenterIP, DNS:$vCenterIP," }
$RequestTemplate = "[ req ]
default_md = sha512
default_bits = 2048
default_keyfile = rui.key
distinguished_name = req_distinguished_name
encrypt_key = no
prompt = no
string_mask = nombstr
req_extensions = v3_req
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = DNS:$ShortName,$IP DNS:$FQDN
[ req_distinguished_name ]
countryName = $Country
stateOrProvinceName = $State
localityName = $City
0.organizationName = $Org
organizationalUnitName = SVCREPLACE
commonName = $FQDN
"
ForEach ($Service in $Services) {
Set-Location $Cert_Dir
if(!(Test-Path $Service)) { new-Item $Service -Type Directory }
Set-Location $Service
# Create CSR and private key
$Out = $RequestTemplate -replace "SVCREPLACE", $Service | Out-File "$Cert_Dir\$Service\$Service.cfg" -Encoding Default -Force
OpenSSL req -new -nodes -out "$Cert_Dir\$Service\$Service.csr" -keyout "$Cert_Dir\$Service\rui-orig.key" -config "$Cert_Dir\$Service\$Service.cfg"
OpenSSL rsa -in "$Cert_Dir\$Service\rui-orig.key" -out "$Cert_Dir\$Service\rui.key"
Remove-Item rui-orig.key
}
}
Function CreateESXCSR {
# Create RSA private keys and CSR
ForEach ($Service in $Services) {
$POS = $Service.IndexOf(".")
$Script:Shortname = $Service.Substring(0, $POS)
$RequestTemplate = "[ req ]
default_md = sha512
default_bits = 2048
default_keyfile = rui.key
distinguished_name = req_distinguished_name
encrypt_key = no
prompt = no
string_mask = nombstr
req_extensions = v3_req
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = DNS:$ShortName, DNS:$Service
[ req_distinguished_name ]
countryName = $Country
stateOrProvinceName = $State
localityName = $City
0.organizationName = $Org
commonName = $Service
"
Set-Location $Cert_Dir
if(!(Test-Path $Service)) { new-Item $Service -Type Directory }
Set-Location $Service
# Create CSR and private key
$Out = $RequestTemplate -replace "SVCREPLACE", $Service | Out-File "$Cert_Dir\$Service\$Service.cfg" -Encoding Default -Force
OpenSSL req -new -nodes -out "$Cert_Dir\$Service\$Service.csr" -keyout "$Cert_Dir\$Service\rui-orig.key" -config "$Cert_Dir\$Service\$Service.cfg"
OpenSSL rsa -in "$Cert_Dir\$Service\rui-orig.key" -out "$Cert_Dir\$Service\rui.key"
Remove-Item rui-orig.key
}
}
Function OnlineMint {
#Mint certificates from online Microsoft CA
# initialize objects to use for external processes
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
$certsRequireApproval = $false
ForEach ($Service in $Services) {
# submit the CSR to the CA
$psi.FileName = "certreq.exe"
$psi.Arguments = @("-submit -attrib `"$Template`" -config `"$ISSUING_CA`" -f `"$Cert_Dir\$Service\$Service.csr`" `"$Cert_Dir\$Service\rui.crt`"")
write-host "Submitting certificate request for $Service"
[void]$process.Start()
$cmdOut = $process.StandardOutput.ReadToEnd()
if ($cmdOut.Trim() -like "*request is pending*")
{
# Output indicates the request requires approval before we can download the signed cert.
$Script:CertsWaitingForApproval = $true
# So we need to save the request ID to use later once they're approved.
$reqID = ([regex]"RequestId: (\d+)").Match($cmdOut).Groups[1].Value
if ($reqID.Trim() -eq [String]::Empty)
{
write-error "Unable to parse RequestId from output."
write-debug $cmdOut
Exit
}
write-host "RequestId: $reqID is pending" -ForegroundColor Yellow
# Save the request ID to a file that OnlineMintResume can read back in later
$reqID | out-file "$Cert_Dir\$Service\requestid.txt"
}
else
{
# Output doesn't indicate a pending request, so check for a signed cert file
if (!(Test-Path $Cert_Dir\$Service\rui.crt)) {
Write-Error "Certificate request failed or was unable to download the signed certificate."
Write-Error "Verify that the ISSUING_CA variable is set correctly."
Write-Debug $cmdOut
Exit
}
}
}
if ($Script:CertsWaitingForApproval) {
write-host
write-host "One or more certificate requests require manual approval before they can be downloaded."
Write-host "Contact your CA administrator to approve the request IDs listed above."
write-host "To resume use Option 3 for Windows vCenter, 9 for vCenter Appliance or 13 for ESXi Hosts"
}
}
Function OnlineMintResume {
#Resume the minting process for certificates from online Microsoft CA that required approval
# initialize objects to use for external processes
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
ForEach ($Service in $Services) {
# skip if there's no requestid.txt file
if (!(Test-Path "$Cert_Dir\$Service\requestid.txt")) { continue }
$reqID = Get-Content "$Cert_Dir\$Service\requestid.txt"
write-verbose "Found RequestId: $reqID for $Service"
# retrieve the signed certificate
$psi.FileName = "certreq.exe"
$psi.Arguments = @("-retrieve -f -config `"$ISSUING_CA`" $reqID `"$Cert_Dir\$Service\rui.crt`"")
write-host "Downloading the signed $Service certificate"
[void]$process.Start()
$cmdOut = $process.StandardOutput.ReadToEnd()
if (!(test-path "$Cert_Dir\$Service\rui.crt"))
{
# it's not there, so check if the request is still pending
if ($cmdOut.Trim() -like "*request is pending*")
{
$Script:CertsWaitingForApproval = $true
write-host "RequestId: $reqID is pending" -ForegroundColor Yellow
}
else
{
write-warning "There was a problem downloading the signed certificate"
write-warning $cmdOut
continue
}
}
}
if ($Script:CertsWaitingForApproval) {
write-host
write-host "One or more certificate requests require manual approval before they can be downloaded."
Write-host "Contact your CA administrator to approve the request IDs listed above."
write-host "To resume use Option 3 for Windows vCenter, 9 for vCenter Appliance or 13 for ESXi Hosts"
}
}
Function CreatePEMFiles {
# Create PEM files and JKS keystore. Rui.crt files must exist for all services.
# Skip if we have pending cert requests
if ($Script:CertsWaitingForApproval) { return; }
if (Test-Path $Cert_Dir\chain.cer) {
$chaincer = "$Cert_Dir\chain.cer"
}
Else {
$chaincer = "$Cert_Dir\root64.cer"
}
ForEach ($Service in $WServices) {
if (!(test-path $Cert_Dir\$Service\rui.crt)) {
Write-host "$Service rui.crt file not found. Skipping PEM creation. Please correct and re-run." -ForegroundColor Red
continue;
}
elseif ($Service -eq "vCenterSSO") {
OpenSSL pkcs12 -export -in "$Cert_Dir\$Service\rui.crt" -inkey "$Cert_Dir\$Service\rui.key" -certfile "$Chaincer" -name "ssoserver" -passout pass:changeme -out "$Cert_Dir\$Service\ssoserver.p12"
if (test-path $Cert_Dir\$Service\root-trust.jks) {remove-item $Cert_Dir\$Service\root-trust.jks}
keytool -v -importkeystore -srckeystore $Cert_Dir\$Service\ssoserver.p12 -srcstoretype pkcs12 -srcstorepass changeme -srcalias ssoserver -destkeystore $Cert_Dir\$Service\root-trust.jks -deststoretype JKS -deststorepass testpassword -destkeypass testpassword
keytool -v -importcert -noprompt -keystore $Cert_Dir\$Service\root-trust.jks -deststoretype JKS -storepass testpassword -keypass testpassword -file $rootcer -alias root-ca
Copy-Item -Path $Cert_Dir\$Service\rui.key -Destination $Cert_Dir\$Service\ssoserver.key
if (test-path -path $intermcer){
keytool -v -importcert -noprompt -trustcacerts -keystore $Cert_Dir\$Service\root-trust.jks -deststoretype JKS -storepass testpassword -keypass testpassword -file $intermcer -alias intermediate-$intermhash.0
}
Copy-Item -Path $Cert_Dir\$Service\root-trust.jks -Destination $Cert_Dir\$Service\server-identity.jks
cmd /c copy $Cert_Dir\$Service\rui.crt+$chaincer $Cert_Dir\$Service\chain.pem
Copy-Item -Path $Cert_Dir\$Service\chain.pem -Destination $Cert_Dir\$Service\ssoserver.crt
}
else {
OpenSSL pkcs12 -export -in "$Cert_Dir\$Service\rui.crt" -inkey "$Cert_Dir\$Service\rui.key" -certfile "$Chaincer" -name "rui" -passout pass:testpassword -out "$Cert_Dir\$Service\rui.pfx"
$RUI = get-content $Cert_Dir\$Service\rui.crt
$ChainCont = get-content $chaincer -encoding default
$RUI + $ChainCont | out-file $Cert_Dir\$Service\chain.pem -Encoding default
}
Set-Location $Cert_Dir
}
}
Function CreateSSOFiles {
# Create the three SSO properties files, needed to replace SSO certificates
# Skip if we have pending cert requests
if ($Script:CertsWaitingForApproval) { return }
$LookupServiceURL = 'https://' + $FQDN + ':7444/lookupservice/sdk'
$SSOServices = @("gc","admin","sts")
if (Test-Path $Cert_Dir\chain.cer) {
$SSLCert = "$Cert_Dir\chain.cer"
}
Else {
$SSLCert = "$Cert_Dir\root64.cer"
}
ForEach ($SSOService in $SSOServices) {
if ($SSOService -eq "gc") {
$SSOFriendly = "The group check interface of the SSO server"
$SSOType = "groupcheck"
$SSODescription = "The group check interface of the SSO server"
$SSOProtocol = "vmomi"
$SVCURI = "sso-adminserver/sdk/vsphere.local"
}
if ($SSOService -eq "admin") {
$SSOFriendly = "The administrative interface of the SSO server"
$SSOType = "admin"
$SSODescription = "The administrative interface of the SSO server"
$SSOProtocol = "vmomi"
$SVCURI = "sso-adminserver/sdk/vsphere.local"
}
if ($SSOService -eq "sts") {
$SSOFriendly = "STS for Single Sign On"
$SSOType = "sts"
$SSODescription = "The Security Token Service of the Single Sign On server."
$SSOProtocol = "wsTrust"
$SVCURI = "sts/STSService/vsphere.local"
}
$SSOTemplate = "[service]
friendlyName=$SSOFriendly
version=1.5
ownerId=
productId=product:sso
type=urn:sso:$SSOType
description=$SSODescription
[endpoint0]
uri=https://FQDN:7444/$SVCURI
ssl=$SSLCert
protocol=$SSOProtocol
"
$Out = $SSOTemplate -replace "FQDN", $FQDN | Out-File "$Cert_Dir\vCenterSSO\$SSOService.properties" -Encoding Default -Force
}
# Create the three SSO ID files
write-host "Connecting to Lookup Service..."
$output = &"$ssodir\ssolscli.cmd" listServices "$lookupServiceURL"
foreach ($line in $output) {
if ($line.StartsWith("Service ")) {
$linenum = ($output | Select-String $line).LineNumber
if ($linenum -is [int32]) {
$serviceId = $output | Select-Object -Index ($linenum+1)
$type = $output | Select-Object -Index ($linenum+3)
if ($type -like '*sts*') {
$serviceidfilename = "$Cert_Dir\vCenterSSO\sts_id"
Set-Content $serviceidfilename $serviceid.TrimStart("serviceId=")
write-host "Created sts files..."
}
elseif ($type -like '*admin*') {
$serviceidfilename = "$Cert_Dir\vCenterSSO\admin_id"
Set-Content $serviceidfilename $serviceid.TrimStart("serviceId=")
write-host "Created admin files..."
}
elseif ($type -like '*group*') {
$serviceidfilename = "$Cert_Dir\vCenterSSO\gc_id"
Set-Content $serviceidfilename $serviceid.TrimStart("serviceId=")
write-host "Created groupcheck files..."
}
}
}
}
If(!(Test-Path "$Cert_Dir\vCenterSSO\gc_id")) {
Write-host "Unable to connect to Lookup service at $lookupserviceurl. " -ForegroundColor Red
}
}
Function CreateBat {
# Create batch template file for VMware vCenter certificate automation tool
$BatchTemplate = "
@echo off
set sso_cert_chain=$Cert_Dir\vCenterSSO\chain.pem
set sso_private_key=$Cert_Dir\vCenterSSO\ssoserver.key
set sso_node_type=single
set is_cert_chain=$Cert_Dir\vCenterInventoryService\chain.pem
set is_private_key_new=$Cert_Dir\vCenterInventoryService\rui.key
set vc_cert_chain=$Cert_Dir\vCenterServer\chain.pem
set vc_private_key=$Cert_Dir\vCenterServer\rui.key
set ngc_cert_chain=$Cert_Dir\vCenterWebClient\chain.pem
set ngc_private_key=$Cert_Dir\vCenterWebClient\rui.key
set logbrowser_cert_chain=$Cert_Dir\vCenterLogBrowser\chain.pem
set logbrowser_private_key=$Cert_Dir\vCenterLogBrowser\rui.key
set vco_cert_chain=$Cert_Dir\VMwareOrchestrator\chain.pem
set vco_private_key=$Cert_Dir\VMwareOrchestrator\rui.key
set vum_cert_chain=$Cert_Dir\VMwareUpdateManager\chain.pem
set vum_private_key=$Cert_Dir\VMwareUpdateManager\rui.key
set sso_admin_user=$sso_admin
set vc_username=$vc_admin
set last_error=
set ROLLBACK_BACKUP_FOLDER=%~dp0backup
set LOGS_FOLDER=%~dp0logs
set CSR_OUTPUT_FOLDER=%~dp0requests
"
$Out = $BatchTemplate | Out-File "$Cert_Dir\ssl-environment.bat" -Encoding Default -Force
Write-host "Batch file written to $Cert_Dir. Copy over VMware tool file." -ForegroundColor Yellow
}
Function SQLDB {
# Creates a generic SQL database creation script.
$VCDB = Read-Host "Enter vCenter Database Name"
$VUMDB = Read-Host "Enter VUM Database Name"
$Account = Read-Host "Enter vCenter service account (domain\account)"
$SQLTemplate = "
/* Creates vCenter server and VUM databases. */
/* Change login name to vCenter service account */
/* Modify paths, DB, log sizes as needed */
EXEC('CREATE LOGIN [$Account]FROM WINDOWS')
USE MSDB
EXEC sp_grantdbaccess ""$Account""
EXEC sp_addrolemember db_owner, ""$Account""
USE master
create database ""$VCDB""
on
( name = '$VCDB',
filename = 'F:\SQLData1\$VCDB.mdf',
size = 4096MB,
filegrowth = 512MB )
log on
( name = '$VCDB log',
filename = 'F:\SQLLogs1\$VCDB.ldf',
size = 384MB,
filegrowth = 128MB )
COLLATE SQL_Latin1_General_CP1_CI_AS;
create database ""$VUMDB""
on
( name = '$VUMDB',
filename = 'F:\SQLData1\$VUMDB.mdf',
size = 1024MB,
filegrowth = 128MB )
log on
( name = '$VUMDB log',
filename = 'F:\SQLLogs1\$VUMDB.ldf',
size = 256MB,
filegrowth = 64MB )
COLLATE SQL_Latin1_General_CP1_CI_AS;
EXEC('ALTER AUTHORIZATION ON DATABASE::""$VCDB"" TO [$Account]')
EXEC('ALTER AUTHORIZATION ON DATABASE::""$VUMDB"" TO [$Account]')
GO
"
$Out = $SQLTemplate | Out-File "$Cert_Dir\vCenter-VUM-DB.sql" -Encoding Default -Force
Write-host "vCenter-VUM-DB.sql written to $Cert_Dir. Modify and run in SQL Manager Studio." -ForegroundColor Yellow
}
Function VCDSN {
$SQLServer = Read-Host "Enter SQL server FQDN"
$DBName = Read-Host "Enter vCenter Database Name"
$Version = Read-Host "What version of SQL server? (2008 or 2012)"
$Encrypt = Read-Host "Do you want SQL SSL encryption? (yes or no)"
$HKLMPath1 = "HKLM:\SOFTWARE\ODBC\ODBC.INI\" + $DBName
$HKLMPath2 = "HKLM:\SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources"
md $HKLMPath1 -ErrorAction silentlycontinue
set-itemproperty -path $HKLMPath1 -name Description -value $DBName
set-itemproperty -path $HKLMPath1 -name Server -value $SQLServer
set-itemproperty -path $HKLMPath1 -name LastUser -value "Administrator"
set-itemproperty -path $HKLMPath1 -name Trusted_Connection -value "Yes"
set-itemproperty -path $HKLMPath1 -name Encrypt -value $Encrypt
set-itemproperty -path $HKLMPath1 -name Database -value $DBName
md $HKLMPath2 -ErrorAction silentlycontinue
if ($version -eq 2008) {
set-itemproperty -path $HKLMPath2 -name "$DBName" -value "SQL Server Native Client 10.0"
set-itemproperty -path $HKLMPath1 -name Driver -value "C:\WINDOWS\system32\sqlncli10.dll"
If(!(test-path "C:\WINDOWS\system32\sqlncli10.dll")) {
Write-Host -Foreground "DarkBlue" -Background "White" "Downloading SQL 2008 R2 SP2 Native Client.."
$SQLurl = "http://download.microsoft.com/download/F/7/B/F7B7A246-6B35-40E9-8509-72D2F8D63B80/sqlncli_amd64.msi"
$SQLexe = "$env:temp\sqlncli.msi"
$wc.DownloadFile($SQLurl,$SQLexe)
$env:path = $env:path + ";$SQLdir"
Write-Host -Foreground "DarkBlue" -Background "White" "Installing SQL 2008 R2 SP2 native client..."
cmd /c msiexec /i $SQLexe /qn IACCEPTSQLNCLILICENSETERMS=YES
Remove-Item $SQLexe
}
}
Else {
set-itemproperty -path $HKLMPath2 -name "$DBName" -value "SQL Server Native Client 11.0"
set-itemproperty -path $HKLMPath1 -name Driver -value "C:\WINDOWS\system32\sqlncli11.dll"
If(!(test-path "C:\WINDOWS\system32\sqlncli11.dll")) {
Write-Host -Foreground "DarkBlue" -Background "White" "Download and install ENU\x64\sqlncli.msi from http://www.microsoft.com/en-us/download/details.aspx?id=35580"
}
}
}
Function VUMDSN {
$SQLServer = Read-Host "Enter SQL server FQDN"
$DBName = Read-Host "Enter VUM Database Name"
$Version = Read-Host "What version of SQL server? (2008 or 2012)"
$Encrypt = Read-Host "Do you want SQL SSL encryption? (yes or no)"
$HKLMPath1 = "HKLM:\SOFTWARE\Wow6432Node\ODBC\ODBC.INI\" + $DBName
$HKLMPath2 = "HKLM:\SOFTWARE\Wow6432Node\ODBC\ODBC.INI\ODBC Data Sources"
md $HKLMPath1 -ErrorAction silentlycontinue
set-itemproperty -path $HKLMPath1 -name Description -value $DBName
set-itemproperty -path $HKLMPath1 -name Server -value $SQLServer
set-itemproperty -path $HKLMPath1 -name LastUser -value "Administrator"
set-itemproperty -path $HKLMPath1 -name Trusted_Connection -value "Yes"
set-itemproperty -path $HKLMPath1 -name Encrypt -value $Encrypt
set-itemproperty -path $HKLMPath1 -name Database -value $DBName
md $HKLMPath2 -ErrorAction silentlycontinue
if ($version -eq 2008) {
set-itemproperty -path $HKLMPath2 -name "$DBName" -value "SQL Server Native Client 10.0"
set-itemproperty -path $HKLMPath1 -name Driver -value "C:\WINDOWS\system32\sqlncli10.dll"
If(!(test-path "C:\WINDOWS\system32\sqlncli10.dll")) {Write-host "Don't forget to install the SQL 2008 client." -ForegroundColor Yellow}
}
Else {
set-itemproperty -path $HKLMPath2 -name "$DBName" -value "SQL Server Native Client 11.0"
set-itemproperty -path $HKLMPath1 -name Driver -value "C:\WINDOWS\system32\sqlncli11.dll"
If(!(test-path "C:\WINDOWS\system32\sqlncli11.dll")) {Write-host "Don't forget to install the SQL 2012 client." -ForegroundColor Yellow}
}
}
Function GetESXHost {
# Construct ESXi Hostname
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 3 ){
Write-host ""
Write-host "Note: If you are resuming a manual/offline request, enter the same"
Write-host "hostname(s) or CSV file as the original request."
Write-host ""
Write-host "1. Manually enter ESXi host(s)"
Write-host "2. Read ESXi hosts from CSV file"
Write-host "3. Quit"
[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 3" }
Write-Host
Switch( $xMenuChoiceA ){
1{ESXHost}
2{ESXCSV}
3{Exit}
default{Exit}
}
}
Function ESXHost {
$Script:Services = (Read-Host "Enter each ESXi FQDN (separate with comma)").split(',') | % {$_.trim()}
}
Function ESXCSV {
# Reads CSV input file of ESXi FQDNs
$CSVFile = Read-Host "Full path to CSV file";
If ( !(Test-Path $CSVFile) )
{
Write-Host "$CSVfile not found" -ForegroundColor Red
ESXCSV
}
else {
$Script:Services = get-content $CSVFile
}
}
Function getWebClient {
# Used for PUTing SSL Certificates on ESXi host
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | out-null
$TASource=@'
namespace Com.Marchview.Net.CertificatePolicy {
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'@
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
# We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Com.Marchview.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
$WCSource=@'
namespace Com.Marchview.Net {
class WebClient : System.Net.WebClient {
protected override System.Net.WebRequest GetWebRequest(System.Uri uri) {
System.Net.WebRequest webRequest = base.GetWebRequest(uri);
webRequest.PreAuthenticate = true;
webRequest.Timeout = 10000;
return webRequest;
}
}
}
'@
$WCResults=$Provider.CompileAssemblyFromSource($Params,$WCSource)
$WCAssembly=$WCResults.CompiledAssembly
$WebClient=$WCAssembly.CreateInstance("Com.Marchview.Net.WebClient")
$WebClient
}
Function GetCredential {
# Used for PUTing SSL Certificates on ESXi host
param(
[String]$UserName,
$Password
)
$CredentialCache=New-Object System.Net.CredentialCache
if ($Password.getType().FullName -eq "System.Security.SecureString") {
$Credential=New-Object System.Net.NetworkCredential($UserName,
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)))
}
else {
$Credential=New-Object System.Net.NetworkCredential($UserName,$Password)
}
$Credential
}
Function getCredentialCache {
# Used for PUTing SSL Certificates on ESXi host
param(
[String]$URIName,
[System.Net.NetworkCredential]$Credential
)
$CredentialCache=New-Object System.Net.CredentialCache
$URI=New-Object System.URI($URIName)
$CredentialCache.Add($URI,"Basic",$Credential)
$CredentialCache
}
Function UploadESXCert {
if ($Script:CertsWaitingForApproval) {EXIT}
ForEach ($Service in $Services) {
# Get password for root account or read from file
$ESXPassFile = $ESXUser + "-credentials"
$ESXPassFile = "$Cert_Dir\$ESXPassFile"
If ( !(Test-Path $ESXPassFile) )
{
Write-Host "No credentials found for " $ESXUser
$Prompt = "Please enter the password for " + $ESXUser
Read-Host -prompt $Prompt -assecurestring | ConvertFrom-SecureString | Out-File $ESXPassFile
}
$ESXPassword = Get-Content $ESXPassFile| ConvertTo-SecureString
# Set directories
$ESXCertFile = "$Cert_Dir\$Service" + "\" + "rui.crt"
$ESXKeyFile = "$Cert_Dir\$Service" + "\" + "rui.key"
# Check if SSL certificate and key exist
If (-not (Test-Path ($ESXKeyFile))) {
"ERROR: Failed to locate the SSL key file at $Cert_Dir\$Service"
exit
}
If (-not (Test-Path ($ESXCertFile))) {
"ERROR: Failed to locate the SSL crt file at $Cert_Dir\$Service"
exit
}
# Set URLs
$ESXiURL = "https://" + $Service
# Create WebClient for uploading the SSL certificate / key
$WebClient=getWebClient
$HostCredential=getCredential $ESXUser $ESXPassword
$HostCredentialCache=getCredentialCache $ESXiURL $HostCredential
$WebClient.Credentials=$HostCredentialCache
# Upload SSL keys
Try
{
$WebClient.UploadFile(($ESXiURL + "/host/ssl_key"),"PUT",$ESXKeyFile)
$WebClient.UploadFile(($ESXiURL + "/host/ssl_cert"),"PUT", $ESXCertFile)
}
Catch
{
$UploadError = $_.Exception.Message
write-host "Upload error occurred for $Service. Check hostname and credentials." -ForegroundColor Red
write-host $_.Exception.Message -ForegroundColor Red
}
if (!$UploadError) {write-host "Certificates uploaded to $Service" -ForegroundColor Yellow }
}
}
### Main ###
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 14 ){
Write-host ""
Write-host "Welcome to the vCenter 5.5 Toolkit" -foregroundcolor Yellow
Write-host "Derek Seaman, VCDX #125, derekseaman.com" -ForegroundColor Yellow
Write-host "vSphere 5.5 series: vexpert.me\Derek55" -ForegroundColor Yellow
Write-host "Use at your own risk; no warranty implied or stated" -ForegroundColor Yellow
Write-host ""
Write-host "Windows vCenter only:"
Write-host ""
Write-host "1. Mint vCenter SSL certs with an online Microsoft CA"
Write-host "2. Create vCenter CSRs for an offline or non-Microsoft CA"
Write-host "3. Process manually downloaded certificates or resume a pending online request"
Write-host "4. Create vCenter Certificate Automation Batch file"
Write-host "5. Create vCenter and VUM SQL database file"
Write-host "6. Create vCenter DSN"
Write-host "7. Create VUM DSN"
write-host ""
Write-host "Linux vCenter Server Appliance (VCSA) only:"
Write-host ""
Write-host "8. Mint VCSA SSL certs with an online Microsoft CA"
Write-host "9. Resume a pending online Microsoft CA request"
Write-host "10. Create VCSA CSRs for an offline or non-Microsoft CA"
Write-host ""
Write-host "ESXi Hosts"
Write-host ""
Write-host "11. Mint ESXi SSL certificate with an online Microsoft CA"
Write-host "12. Create ESXi CSRs for an offline or non-Microsoft CA"
Write-host "13. Install manually downloaded certificates or resume a pending online request"
Write-host ""
Write-host "14. Quit"
[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 14" }
Write-Host
Switch( $xMenuChoiceA ){
1{$Script:Services = $WServices; CheckOpenSSL; WinVCCheck; DownloadRoot; DownloadSub; VCFQDN; CreateCSR; OnlineMint; CAHashes; CreatePEMFiles; CreateSSOFiles}
2{$Script:Services = $WServices; CheckOpenSSL; WinVCCheck; VCFQDN; CreateCSR}
3{$Script:Services = $WServices; CheckOpenSSL; WinVCCheck; DownloadRoot; DownloadSub; VCFQDN; OnlineMintResume; CAHashes; CreatePemFiles; CreateSSOFiles}
4{CreateBat}
5{SQLDB}
6{VCDSN}
7{VUMDSN}
8{$Script:Services = $LServices; CheckOpenSSL; VCFQDN; DownloadRoot; DownloadSub; CreateCSR; OnlineMint }
9{$Script:Services = $LServices; CheckOpenSSL; VCFQDN; DownloadRoot; DownloadSub; OnlineMintResume}
10{$Script:Services = $LServices; CheckOpenSSL; VCFQDN; CreateCSR}
11 {CheckOpenSSL; GetESXHost; CreateESXCSR; OnlineMint; UploadESXCert}
12 {CheckOpenSSL; GetESXHost; CreateESXCSR}
13 {CheckOpenSSL; GetESXHost; OnlineMintResume; UploadESXCert}
14{Exit}
default{Exit}
}