Nutanix Cluster Info Script

July 21, 2020

by Ed McAndrew

Intended Audience Level: Beginner/Intro

Code Sample Type: Complete Script

Nutanix Technologies: Prism Element, General

Minimum Product Version: AOS 5.5+

Script/Code Language: PowerShell

REST API Sample? Yes

REST API Version: v2.0

Mine Nutanix Cluster Information

Code Sample Details

Note this section may be empty, if additional code sample details are not available.
<#
.notes
	##############################################################################
	#	 	 Nutanix Cluster Info Script
	#	 	 Filename			:	  NTNX_Get_Cluster_Info.ps1
	#	 	 Script Version	:	  1.0
	##############################################################################
.prerequisites
	1. Powershell 5 or above ($psversiontable.psversion.major)
	2. Windows Vista or newer.
	3. Set the appropriate variables for your environment.
.synopsis
	Generate 2 CSV files, 1 for cluster information, and 1 for host information.
.disclaimer
	This code is intended as a standalone example. Subject to licensing restrictions defined on nutanix.dev, this can be downloaded, copied and/or modified in any way you see fit.

	Please be aware that all public code samples provided by Nutanix are unofficial in nature, are provided as examples only, are unsupported and will need to be heavily scrutinized and potentially modified before they can be used in a production environment. All such code samples are provided on an as-is basis, and Nutanix expressly disclaims all warranties, express or implied.

	All code samples are © Nutanix, Inc., and are provided as-is under the MIT license. (https://opensource.org/licenses/MIT)
#>
##############################################################################
# Set Variables Below
##############################################################################
$ClusterArrayIP = @("10.0.0.1","10.0.0.2","10.0.0.3") # Define all of your clusters by IPv4 address here!
#//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
# CHANGE NOTHING BELOW HERE!
#//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[string]$my_temperract = $erroractionpreference # set error handling preferences
[string]$erroractionpreference = "silentlycontinue" # set error handling preferences
function isonline([string]$my_testcomputer) {
	write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	write-host "Host: $($my_testcomputer) " -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	$my_pingsuccess = $false
	try {
		$my_ping = new-object system.net.networkinformation.ping
		$my_pingtest = $my_ping.send($my_testcomputer)
	}
	catch{ }
	write-host "[" -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	if ($my_pingtest.status.tostring() -eq "Success") {
		write-host "Online" -nonewline -foregroundcolor GREEN -backgroundcolor BLACK;
		$tmpString = "]"
		foreach($i in 0..($my_seplength-$my_testcomputer.length-17)) { $tmpString += -join " " }
		write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		return $true
	}
	else {
		write-host "Offline" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
		$tmpString = "]"
		foreach($i in 0..($my_seplength-$my_testcomputer.length-18)) { $tmpString += -join " " }
		write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		return $false
	}
 }
function format-size($size) {
    if ($size -gt 1tb) { [string]::format("{0:0.00} TiB", $size / 1tb) }
    elseif ($size -gt 1gb) { [string]::format("{0:0.00} GiB", $size / 1gb) }
    elseif ($size -gt 1mb) { [string]::format("{0:0.00} MB", $size / 1mb) }
    elseif ($size -gt 1kb) { [string]::format("{0:0.00} KB", $size / 1kb) }
    elseif ($size -gt 0)   { [string]::format("{0:0.00} B", $size) }
    else { "N/A" }
}
function mformat-string($string) {
	if (-not ([string]::IsNullOrEmpty($string))) {
		return [string]$string
	}
	return "N/A"
}
function collect_cluster_info($targetIP) {
	## Collect Cluster Info
	$tmpString1 = "..Parsing Cluster Data"
	write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	write-host ("{0}" -f $tmpString1) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	try {
		$restAPIURI = "https://$($targetIP):9440/PrismGateway/services/rest/v2.0/cluster/"
		$restResponse = Invoke-RestMethod -Method Get -Uri $restAPIURI -Headers @{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"
		$arrCluster = @()
		$tmpClusterObj = new-object psobject
		[int]$my_int = 0
		$restResponse | % {
			$myClusterName = $_.name
			$cluster_name = mformat-string($_.name)
			if (-not $clusterHash.containskey($targetIP)) { $clusterHash.add($targetIP,$cluster_name) }
			write-progress -id 2 -parentid 1 -activity " " -status "Enumerating JSON values..." -percentcomplete ($my_int / @($restResponse).count * 100)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Name" -value $cluster_name
			$cluster_id = mformat-string($_.id)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster ID" -value $cluster_id
			$cluster_uuid = mformat-string($_.uuid)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster UUID" -value $cluster_uuid
			$cluster_incarnation_id = mformat-string($_.cluster_incarnation_id)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Incarnation ID" -value $cluster_incarnation_id
			$cluster_external_ipaddress = mformat-string($_.cluster_external_ipaddress)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Virtual IP Address" -value $cluster_external_ipaddress.trim('{}')
			$cluster_external_data_services_ipaddress = mformat-string($_.cluster_external_data_services_ipaddress)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster iSCSI Data Services IP" -value $cluster_external_data_services_ipaddress.trim('{}')
			$hypervisor_types = mformat-string($_.hypervisor_types)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Hypervisor" -value $hypervisor_types.trim('{k}')
			$timezone = mformat-string($_.timezone)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Timezone" -value $timezone
			$support_verbosity_type = mformat-string($_.support_verbosity_type)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Support Verbosity" -value $support_verbosity_type
			$version = mformat-string($_.version)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster AOS Version" -value $version
			$full_version = mformat-string($_.full_version)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Full AOS Version" -value $full_version
			$ncc_version = mformat-string($_.ncc_version)
			$tmpClusterObj | add-member -membertype noteproperty -name "Cluster NCC Version" -value $ncc_version
			$i = 1
			foreach ($nameserver in $_.name_servers) {
				$tmpClusterObj | add-member -membertype noteproperty -name "Cluster Name Server #$($i)" -value $nameserver.trim('{}')
				$i++
			}
			$i = 1
			foreach ($ntpserver in $_.ntp_servers) {
				$tmpClusterObj | add-member -membertype noteproperty -name "Cluster NTP Server #$($i)" -value $ntpserver.trim('{}')
				$i++
			}
			$arrCluster += $tmpClusterObj
			$my_int++
		}
		$arrCluster | export-csv $file1 -append -notypeinformation -force
		write-host " [" -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "OK" -nonewline -foregroundcolor GREEN -backgroundcolor BLACK;
		$tmpString = "]"
		foreach($i in 0..($my_seplength-29)) { $tmpString += -join " " }
		write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	}
	catch {
		write-host " [" -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		if ($_ -like '*Password*failed*') {
			write-host "Bad Password" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-39)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
		elseif ($_ -like '*Bad*credentials*') {
			write-host "Bad Credentials" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-42)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
		else {
			write-host "FAIL" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-31)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
	}
	write-progress -id 2 -parentid 1 -activity " " -status "Enumerating JSON values..." -complete
	## Collect Cluster Info
}
function collect_node_info($targetIP) {
	## Collect Disk Count
	$tmpString1 = "..Parsing Node Data"
	write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	write-host ("{0}" -f $tmpString1) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	try {
		$restAPIURI = "https://$($targetIP):9440/PrismGateway/services/rest/v2.0/disks/"
		$restResponse = Invoke-RestMethod -Method Get -Uri $restAPIURI -Headers @{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"
		$driveHash = @{}
		$tmpHash = @{}
		$tmpStorageHash = @{};$restResponse.entities | get-member -membertype properties | foreach { $tmpStorageHash.add($_.name,$restResponse.entities.($_.name)) }
		$i = 0
		$tmpStorageHash['cvm_ip_address'] | % {
			$tmpIP = $_
			$nodeIPId = $tmpIP.split('.')[3]
			$driveType = $tmpStorageHash['storage_tier_name'][$i]
			if (-not $tmpHash.containskey($nodeIPId)) { $tmpHash.add($nodeIPId,$driveType) }
			else { $tmpVal = $tmpHash[$nodeIPId]; $tmpHash[$nodeIPId] += ",$($driveType)" }
			$i++
		}
		foreach ($h in $tmphash.getenumerator()) { $my_HDD = 1;$my_SSD = 1; $h.value.split(",") | foreach { switch($_) { "HDD" { $my_HDD++ }; "SSD" { $my_SSD++ } } }; if (-not $driveHash.containskey($h.name)) { $driveHash.add($h.name,"$($my_HDD)|$($my_SSD)") } }
		## Collect Disk Count
		$restAPIURI = "https://$($targetIP):9440/PrismGateway/services/rest/v2.0/hosts/"
		$restResponse = Invoke-RestMethod -Method Get -Uri $restAPIURI -Headers @{Authorization = "Basic $base64AuthInfo" } -Credential $credential -ContentType "application/json"
		$arrNode = @()
		[int]$my_int = 0
		$restResponse.entities | % {
			write-progress -id 2 -parentid 1 -activity " " -status "Enumerating JSON values..." -percentcomplete ($my_int / @($restResponse.entities).count * 100)
			$myEntities = $_
			$tmpnodeobj = new-object psobject
			$cluster_name = mformat-string($clusterHash.Item($targetIP))
			$tmpNodeObj | add-member -membertype noteproperty -name "Cluster Name" -value $cluster_name
			$node_name = mformat-string($myEntities.name)
			$tmpNodeObj | add-member -membertype noteproperty -name "Host Name" -value $node_name
			$hypervisor_address = mformat-string($myEntities.hypervisor_address)
			$tmpNodeObj | add-member -membertype noteproperty -name "Hypervisor IP" -value $hypervisor_address.trim('{}')
			$controller_address = mformat-string($myEntities.controller_vm_backplane_ip)
			$tmpNodeObj | add-member -membertype noteproperty -name "Controller VM IP" -value $controller_address.trim('{}')
			$ipmi_address = mformat-string($myEntities.ipmi_address)
			$tmpNodeObj | add-member -membertype noteproperty -name "IPMI IP" -value $ipmi_address.trim('{}')
			$node_serial = mformat-string($myEntities.serial)
			$tmpNodeObj | add-member -membertype noteproperty -name "Node Serial" -value $node_serial
			$block_serial = mformat-string($myEntities.block_serial)
			$tmpNodeObj | add-member -membertype noteproperty -name "Block Serial" -value $block_serial
			$block_model = mformat-string($myEntities.block_model_name)
			$tmpNodeObj | add-member -membertype noteproperty -name "Block Model" -value $block_model
			$tmpStorageHash=@{}; $myentities.usage_stats | get-member -membertype properties | foreach { if ($myentities.usage_stats.($_.name) -ne '-1') { $tmpStorageHash.add($_.name,$myentities.usage_stats.($_.name)) } else { $tmpStorageHash.add($_.name,0) } }
			$tmpNodeObj | add-member -membertype noteproperty -name "Storage Capacity" -value "$(format-size($tmpStorageHash['storage.capacity_bytes']))"
			$tmpNodeObj | add-member -membertype noteproperty -name "Disks" -value "HDD: $($driveHash[$myEntities.controller_vm_backplane_ip.split('.')[3]].split('|')[0]) SSD: $($driveHash[$myEntities.controller_vm_backplane_ip.split('.')[3]].split('|')[1])"
			$tmpNodeObj | add-member -membertype noteproperty -name "Memory" -value  "$(format-size($myEntities.memory_capacity_in_bytes))"
			$cpu_capacity = $_.cpu_capacity_in_hz / 1000000000; if ($cpu_capacity -eq 0) { $cpu_capacity = "N/A" } else { [string]$cpu_capacity += " GHz" }
			$tmpNodeObj | add-member -membertype noteproperty -name "CPU Capacity" -value $cpu_capacity
			$cpu_model = mformat-string($myEntities.cpu_model)
			$tmpNodeObj | add-member -membertype noteproperty -name "CPU Model" -value $cpu_model
			$cpu_cores = mformat-string($myEntities.num_cpu_cores)
			$tmpNodeObj | add-member -membertype noteproperty -name "No. of CPU Cores" -value $cpu_cores
			$cpu_cores = mformat-string($myEntities.num_cpu_cores)
			$tmpNodeObj | add-member -membertype noteproperty -name "No. of Sockets" -value $myEntities.num_cpu_sockets
			$num_vms = mformat-string($myEntities.num_vms)
			$tmpNodeObj | add-member -membertype noteproperty -name "No. of VMs" -value $num_vms
			$oplog_disk_pct = mformat-string($myEntities.oplog_disk_pct)
			$tmpNodeObj | add-member -membertype noteproperty -name "Oplog Disk %" -value "$($oplog_disk_pct)%"
			$cpu_cores = mformat-string($myEntities.num_cpu_cores)
			$tmpNodeObj | add-member -membertype noteproperty -name "Oplog Disk Size" -value "$(format-size($myEntities.oplog_disk_size))"
			$monitored = mformat-string($myEntities.monitored)
			$tmpNodeObj | add-member -membertype noteproperty -name "Monitored" -value $monitored
			$hypervisor_full_name = mformat-string($myEntities.hypervisor_full_name)
			$tmpNodeObj | add-member -membertype noteproperty -name "Hypervisor" -value $hypervisor_full_name
			$arrNode += $tmpNodeObj
			$my_int++
		}
		$arrNode | export-csv $file2 -append -notypeinformation -force
		write-host " [" -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "OK" -nonewline -foregroundcolor GREEN -backgroundcolor BLACK;
		$tmpString = "]"
		foreach($i in 0..($my_seplength-26)) { $tmpString += -join " " }
		write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	}
	catch {
		write-host " [" -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
		if ($_ -like '*Password*failed*') {
			write-host "Bad Password" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-36)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
		elseif ($_ -like '*Bad*credentials*') {
			write-host "Bad Credentials" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-39)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
		else {
			write-host "FAIL" -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			$tmpString = "]"
			foreach($i in 0..($my_seplength-28)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
	}
	write-progress -id 2 -parentid 1 -activity " " -status "Enumerating JSON values..." -complete
}

if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type) {
	$certCallback = @"
		using System;
		using System.Net;
		using System.Net.Security;
		using System.Security.Cryptography.X509Certificates;
		public class ServerCertificateValidationCallback {
			public static void Ignore() {
				if(ServicePointManager.ServerCertificateValidationCallback ==null) { ServicePointManager.ServerCertificateValidationCallback += delegate ( Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors )  { return true; }; }
			}
		}
"@
    Add-Type $certCallback
 }
[ServerCertificateValidationCallback]::Ignore()
[net.servicepointmanager]::securityprotocol = [net.securityprotocoltype]::tls12
$my_scriptpath = $myinvocation.mycommand.path # grab the full path to the scripts execution directory/location.
$my_workingdir = split-path $my_scriptpath # split the execution full path from the filename to create a working directory variable.
$file1 = "$($my_workingdir)\Nutanix_Clusters_$((get-date -uformat '%m%d%Y')).csv"
$file2 = "$($my_workingdir)\Nutanix_Nodes_$((get-date -uformat '%m%d%Y')).csv"
[int]$my_int1 = 0
if(test-path $file1) { remove-item $file1}
if(test-path $file2) { remove-item $file2}
$my_seplength = $file1.length+10
foreach($i in 0..($my_seplength)) { $my_linediv += "-" }
write-host $my_linediv -foregroundcolor BLACK -backgroundcolor DARKGRAY;
write-host "Collecting " -nonewline -foregroundcolor BLACK -backgroundcolor DARKGRAY;
write-host "NUTANI" -nonewline -foregroundcolor BLUE -backgroundcolor DARKGRAY;
write-host "X" -nonewline -foregroundcolor GREEN -backgroundcolor DARKGRAY;
$tmpString = " Cluster Information"
foreach($i in 0..($my_seplength-38)) { $tmpString += -join " " }
write-host ("{0}" -f $tmpString) -foregroundcolor BLACK -backgroundcolor DARKGRAY;
write-host $my_linediv -foregroundcolor BLACK -backgroundcolor DARKGRAY;
$clusterHash = @{}
foreach ($cluster in $clusterarrayip) {
	if (isonline($cluster.trim())) {
		write-progress -id 1 -Activity "Collecting data" -status "Parsing REST data for $($cluster)" -percentcomplete ($my_int1 / $clusterarrayip.count * 100)
		$credentials = $host.ui.promptforcredential("Credentials for $($cluster)", "Please enter your user name and password for $($cluster)", "", "")
		if ($credentials) {
			$credential = New-Object –TypeName "System.Management.Automation.PSCredential" -ArgumentList $credentials.username, $credentials.password
			$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $credentials.username,$credentials.password)))
			collect_cluster_info($cluster)
			collect_node_info($cluster)
		}
		else {
			$tmpString = "..No credentials!"
			write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
			foreach($i in 0..($my_seplength-19)) { $tmpString += -join " " }
			write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor RED -backgroundcolor BLACK;
			write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
		}
		$my_int1++
	}
}
write-progress -id 1 -Activity "Collecting data" -status "Done..." -complete
write-host $my_linediv -foregroundcolor BLACK -backgroundcolor DARKGRAY;
write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
$tmpString = "Done!"
foreach($i in 0..($my_seplength-7)) { $tmpString += -join " " }
write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
if((test-path $file1) -or (test-path $file2)) {
	write-host $my_linediv -foregroundcolor BLACK -backgroundcolor DARKGRAY;
}
if(test-path $file1) {
	write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	$tmpString = "File 1: $($file1)"
	foreach($i in 0..(($my_seplength-$tmpString.length)-2)) { $tmpString += -join " " }
	write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
}
if(test-path $file2) {
	write-host "|" -nonewline -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
	$tmpString = "File 2: $($file2)"
	foreach($i in 0..(($my_seplength-$tmpString.length)-2)) { $tmpString += -join " " }
	write-host ("{0}" -f $tmpString) -nonewline -foregroundcolor GRAY -backgroundcolor BLACK;
	write-host "|" -foregroundcolor DARKGRAY -backgroundcolor DARKGRAY;
}
write-host $my_linediv -foregroundcolor BLACK -backgroundcolor DARKGRAY;
$erroractionpreference = $my_temperract
exit
########

SSH PUBLIC KEY

Copy the SSH public key below.  In BASH shell environments, for example, this file could be saved to ~/.ssh/nutanix_demo.pub

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCm+7N2tjmJw5jhPmD8MS6urZQJB42ABh73ffGQSJ0XUHgdEDfjUDFkLK0wyJCe0sF5QJnh07UQn0F0BUnBi+VwehPGeODh6S43OP5YS/14L0fyntFI06B9lckx/ygRNu82sHxXCX+6VVUFPOPC+sz6j1DQswKY9d4cEYnaMBGSzqRxrqAIf6aWIKTJTYKPFY0zaUZ6ow2iwS0Nlh5EqaXsEBWkqMmr7/auP9GV/adUgzFrGLJklYBdfH575SIK6/PZL6wNT0jE9LmFlEm7dI01ZWPclBuV16FzRyrnzmWr/ebY62A04vYBtR0vyfEfsW2ZgxgD6aAE6+ytj0v19y0elRtOaeTySN/HlXh7owKWCHnlXNpTUiSDP8SQ8LRARkhQu3KEDL0ppGCrSF87oFkp1gPzf92U+UK3LaNMMjZXMOy0zLoLEdLtbQo6S8iHggDoX4NI4sWWxcX0mtadvjy/nIOvskk9IXasQh0u0MT9ARQY5VXPluKDtEVdeow9UbvgJ1xxNkphUgsWjCiy+sjgapsuZvWqKM6TPT1i24XYaau+/Fa0vhjLb8vCMWrrtkRwGt4re243NDYcYWTzVZUFuUK0w1wqt77KgjCCeyJdsZNwrh15v780Fjqpec3EGVA0xyNbF0jn/tsnYy9jPh/6Cv767EratI97JhUxoB4gXw== no-reply@acme.com