ps/Modules/Alkami.PowerShell.ServiceFabric/Public/Connect-AlkamiServiceFabricCluster.ps1

137 lines
6.4 KiB
PowerShell
Raw Permalink Normal View History

2023-05-30 22:51:22 -07:00
function Connect-AlkamiServiceFabricCluster {
<#
.SYNOPSIS
Initiates a Service Fabric cluster connection, and stores the connection to the global scope for the session.
No action is taken if you are already connected to the cluster at the provided hostname.
.PARAMETER hostname
The host name of any server in the Service Fabric cluster.
.PARAMETER ServerCertificateCommonName
The common name of the server certificate to authenticate to the cluster with.
.PARAMETER CertificateCommonName
The common name of the server OR client certificate to authenticate to the cluster with.
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false, ParameterSetName = "WindowsAuth")]
[Parameter(Mandatory=$false, ParameterSetName = "CertAuth")]
[string]$Hostname = "localhost",
[Parameter(Mandatory=$true, ParameterSetName = "CertAuth")]
[string]$ServerCertificateCommonName,
[Parameter(Mandatory=$true, ParameterSetName = "CertAuth")]
[string]$CertificateCommonName
)
$loglead = (Get-LogLeadName);
$endpoint = "$($hostname):19000";
# Check if we are already connected to this particular cluster endpoint.
Write-Verbose "$loglead Checking for existing Service Fabric connection.";
if(($null -ne $Global:ClusterConnection) -and ($Global:ClusterConnection.ConnectionEndpoint -eq $endpoint)) {
Write-Verbose "$loglead Found existing connection.";
return;
}
# We can't connect to a cluster if there is no hostname.
if([string]::IsNullOrWhiteSpace($hostname)) {
Write-Error "$loglead No hostname provided to connect to.";
return;
}
# If the connection certificate was not explicitly provided, look it up on the remote machine.
if([string]::IsNullOrWhiteSpace($CertificateCommonName)) {
Write-Verbose "$loglead Certificate common name was not specified. Looking up certificate to use from remote machine.";
$clusterManifestLocation = "C:\ProgramData\SF\clusterManifest.xml";
$clusterManifestLocation = Get-UncPath -filePath $clusterManifestLocation -ComputerName $hostname -IgnoreLocalPaths;
if(!(Test-Path $clusterManifestLocation)) {
Write-Error "$loglead : Could not find Cluster Manifest config file at '$clusterManifestLocation'. Is this server running Service Fabric?";
return;
}
# Read the certificate common name to connect to the cluster with.
$namespace = @{ x = "http://schemas.microsoft.com/2011/01/fabric" };
$serverCertNode = (Select-Xml -Path $clusterManifestLocation -XPath "//x:ServerCertificate" -Namespace $namespace) | Select-Object -ExpandProperty Node -First 1;
if(!([string]::IsNullOrWhiteSpace($serverCertNode.X509FindValue))) {
$CertificateCommonName = $serverCertNode.X509FindValue;
} else {
Write-Verbose "$loglead Could not locate a certificate name in the cluster manifest. Falling back to Windows Authentication."
}
}
# If there is no cert common name, connect with windows authentication.
if([string]::IsNullOrWhiteSpace($CertificateCommonName)) {
Write-Verbose "$loglead Opening connection to Service Fabric cluster at endpoint $endpoint with Windows Authentication";
$connectionResult = (Connect-ServiceFabricCluster -ConnectionEndpoint $endpoint -WindowsCredential);
} else {
# Otherwise connect with a certificate.
Write-Verbose "$loglead Searching for certificate $CertificateCommonName";
# Search for the cert in the current user store location.
$storeLocation = "CurrentUser";
$cert = (Find-CertificateByName -CommonName $CertificateCommonName -StoreLocation $storeLocation -StoreName My);
if($null -eq $cert) {
Write-Verbose "$loglead Could not locate certificate $CertificateCommonName in the user store location."
}
# Search for the cert in the local machine store location.
if($null -eq $cert) {
$storeLocation = "LocalMachine";
$cert = (Find-CertificateByName -CommonName $CertificateCommonName -StoreLocation $storeLocation -StoreName My);
if($null -eq $cert) {
Write-Verbose "$loglead Could not locate certificate $CertificateCommonName in the machine store location."
}
}
# Return out if the certificate could not be located in either store.
if($null -eq $cert) {
Write-Error "$loglead Could not locate certificate $CertificateCommonName in the user or machine stores.";
return;
}
Write-Verbose "$loglead Opening connection to Service Fabric cluster at endpoint $endpoint with certificate $CertificateCommonName";
$connectArgs = $null;
# If the server cert common name is specified, they are connecting with an explicit server common name + client cert common name
if(!([string]::IsNullOrWhiteSpace($ServerCertificateCommonName))) {
$connectArgs = @{
ConnectionEndpoint = $endpoint;
X509Credential = $True;
StoreLocation = "CurrentUser"; # Intentionally only search the CurrentUser store.
StoreName = "My";
ServerCommonName = $ServerCertificateCommonName;
FindType = "FindBySubjectName";
FindValue = $CertificateCommonName;
}
} else {
# Otherwise we are dealing with an admin cert. Connect using the same certificate for admin/client auth.
$connectArgs = @{
ConnectionEndpoint = $endpoint;
X509Credential = $True;
StoreLocation = $storeLocation;
StoreName = "My";
ServerCertThumbprint = $cert.Thumbprint;
FindType = 'FindByThumbprint';
FindValue = $cert.Thumbprint;
}
}
$connectionResult = (Connect-ServiceFabricCluster @ConnectArgs);
}
$success = $connectionResult[0];
if(!$success) {
Write-Error "$loglead Could not open connection to Service Fabric cluster at $endpoint";
return;
}
# Service fabric sets $ClusterConnection to the local scope.
# Escalate that scope to the global-scope.
$Global:ClusterConnection = $ClusterConnection;
Write-Host "$loglead Connected to Service Fabric cluster at endpoint $endpoint";
}