PowerCLI NVMe TBW push to vROps API

PowerCLI, vROps

Idea – Homelab, wanted to push the GBW and TBW (Terabytes Written) metric on an ESXi 7.0 host NVMe drive to vROps. SATA drives need smartctl to be install in where there is not an ESXi 7.0 VIB https://www.virten.net/2016/05/determine-tbw-from-ssds-with-s-m-a-r-t-values-in-esxi-smartctl/

The PowerCLI script will login to vCenter, use get-esxcli -V2 to pull the NVMe drive metrics and then run a POST to the vROps API for the single ESXi host in scope with those metics to create a new NVMe propery in vROps.

The Model will not have a new plot point since the model will not change. The GBW will have more plots points vs the TBW since you need 100 Gigabyes to change the first decimal point.

Limitations – Only one ESXi host is specified in the script and you have to fill in the host resource object ID from vROps. Securty and scripting best practives are not used. No warrenty 🙂

 

Make sure to run these two powershell commands in the same folder as the script for the vROps and VCSA login accounts.
(get-credential).password | ConvertFrom-SecureString | set-content vrops.pass
(get-credential).password | ConvertFrom-SecureString | set-content vcsa.pass

In the ps1, Fill in the Six Variables.

 

# Found https://vmscribble.com/powercli/powercli-nvme-tbw-push-to-vrops-api
# Make sure to run these command in the same folder as the script for the vROps and VCSA login accounts.
# (get-credential).password | ConvertFrom-SecureString | set-content vrops.pass
# (get-credential).password | ConvertFrom-SecureString | set-content vcsa.pass

# Variables to edit
$vROPsServer = "vrops.my.lab"
$vROPSUser = "admin"
$esxihostid = "c08254d8-ca69-490e-8670-c2f696dd1a91"

$esxihostname = "esxi-dell.my.lab"
$vCenterfqdn = "vcsa1.my.lab"
$vCenteraccount = "Administrator@vsphere.local"

# vCenter credentials 
$Passworddecodevcsa = Get-Content vcsa.pass | ConvertTo-SecureString 
$vcsacredential = New-Object System.Management.Automation.PsCredential("$vCenteraccount",$Passworddecode)
$vcsaPassword = $vcsacredential.GetNetworkCredential().Password

# Connect to your vCenter
Connect-VIServer -Server $vCenterfqdn -User $vCenteraccount -Password $vcsaPassword | out-null

# Pull NVMe model/GBW/TBW - thanks - https://www.virten.net/2020/03/how-to-check-nvme-drives-tbw-in-esxi-with-powercli/

Foreach ($vmhost in Get-VMHost -Name $esxihostname ) {
    $esxcli = get-esxcli -V2 -vmhost $vmhost
    $devices = $esxcli.nvme.device.list.Invoke()
    Foreach ($device in $devices) {
        $nvme = $esxcli.nvme.device.get.CreateArgs()
        $nvme.adapter = $device.HBAName
        $Info = "" | Select VMHost, HBA, Model, DataUnitsWritten, GBW, TBW
        $Info.VMHost = $vmhost.Name
        $Info.HBA = $device.HBAName
        $Info.Model = ($esxcli.nvme.device.get.invoke($nvme) | Select-Object ModelNumber).ModelNumber
        $Info.DataUnitsWritten = [int]($esxcli.nvme.device.log.smart.get.Invoke($nvme) |Select-Object DataUnitsWritten).DataUnitsWritten
        $Info.GBW = [math]::round($Info.DataUnitsWritten*512000/1Gb)
        $Info.TBW = [math]::round($Info.DataUnitsWritten*512000/1Tb, 1)
        $AllInfo += $Info
    }
}

# Record NVMe model/GBW/TBW output as Variables for the vROps API POST.
$NVMemodel = $Info.Model
$NVMeGBW = $Info.GBW
$NVMeTBW = $Info.TBW

# Disconnect from the vCenter
Disconnect-VIServer $vCenterfqdn -Confirm:$false

# vROps credentials 
$Passworddecode = Get-Content vrops.pass | ConvertTo-SecureString 
$credential = New-Object System.Management.Automation.PsCredential("$vROPSUser",$Passworddecode)
$vROPsPassword = $credential.GetNetworkCredential().Password

# Powershell API connecton - thanks - https://socialvirtualcloud.com/injecting-data-into-vrops-via-api-from-external-system/
# Defining REST API URLS for use
$BaseURL = "https://" + $vROPsServer + "/suite-api/api/"
$BaseAuthURL = "https://" + $vROPsServer + "/suite-api/api/auth/token/acquire"
$Type = "application/json"

# Creating JSON for Auth Body
$AuthJSON =
        "{
          ""username"": ""$vROPSUser"",
          ""password"": ""$vROPsPassword""
        }"
# Authenticating with API
    Try 
    {
        $vROPSSessionResponse = Invoke-RestMethod -Method POST -Uri $BaseAuthURL -Body $AuthJSON -ContentType $Type
    }
    Catch 
    {
        $_.Exception.ToString()
        $error[0] | Format-List -Force
    }

# Extracting the session ID from the response
    $vROPSSessionHeader = @{"Authorization"="vRealizeOpsToken "+$vROPSSessionResponse.'auth-token'.token
    "Accept"="application/json"}
	
	
# tested via swagger Resource addPropertiesUsingPOST - Add Properties to a Resource along with associating an adapter instance of the specified adapter kind as the source of data
# thanks - https://vman.ch/vrops-custom-network-stats-for-hostsystems/

[xml]$MetricXML = @('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ops:property-contents xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<ops:property-content statKey="NVMe|TBW">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMeTBW+'</ops:values>
    </ops:property-content>
	<ops:property-content statKey="NVMe|GBW">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMeGBW+'</ops:values>
    </ops:property-content>
	<ops:property-content statKey="NVMe|Model">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMemodel+'</ops:values>
	</ops:property-content>
</ops:property-contents>'
    )


# vROPs POST URL using the esxi host id found in the variables.
$posturl = "$BaseURL/resources/$esxihostid/properties"
 
# One liner to POST into vROps 
Invoke-RestMethod -Method POST -uri $posturl -Body $MetricXML -Headers $vROPSSessionHeader -ContentType "application/xml;charset=utf-8" -TimeoutSec 120

Setup –
VMware.PowerCLI Version: 12.3.0.17860403
vRealize Operations Manager Version: 8.4.0 (17863947)
vROps has an internal CA signed cert using XCA – https://vmscribble.com/vcenter/vmware-vcsa-use-xca-for-root-and-intermediate-certificate-authority/

If the vROps cert is the out of the box self signed one, you will run into this error:
System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. —> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
Workaround is to add the “using System.Security.Cryptography.X509Certificates;” section to the script from https://michaelryom.dk/vrops-api-consumed-with-powershell/

Tip –
Add to the script to run via the Windows Server Task Scheduler (repeat task every 5 minutes) https://vmscribble.com/powercli/automate-powercli-scripts-via-the-windows-server-2012-task-scheduler/

 

Idea

Idea – Homelab, wanted to push the GBW and TBW (Terabytes Written) metric on an ESXi 7.0 host NVMe drive to vROps. SATA drives need smartctl to be install in where there is not an ESXi 7.0 VIB https://www.virten.net/2016/05/determine-tbw-from-ssds-with-s-m-a-r-t-values-in-esxi-smartctl/

The PowerCLI script will login to vCenter, use get-esxcli -V2 to pull the NVMe drive metrics and then run a POST to the vROps API for the single ESXi host in scope with those metics to create a new NVMe propery in vROps.

The Model will not have a new plot point since the model will not change. The GBW will have more plots points vs the TBW since you need 100 Gigabyes to change the first decimal point.

Limitations – Only one ESXi host is specified in the script and you have to fill in the host resource object ID from vROps. Securty and scripting best practives are not used. No warrenty 🙂

 

Prerequisites

Make sure to run these two powershell commands in the same folder as the script for the vROps and VCSA login accounts.
(get-credential).password | ConvertFrom-SecureString | set-content vrops.pass
(get-credential).password | ConvertFrom-SecureString | set-content vcsa.pass

In the ps1, Fill in the Six Variables.

 

The Script
# Found https://vmscribble.com/powercli/powercli-nvme-tbw-push-to-vrops-api
# Make sure to run these command in the same folder as the script for the vROps and VCSA login accounts.
# (get-credential).password | ConvertFrom-SecureString | set-content vrops.pass
# (get-credential).password | ConvertFrom-SecureString | set-content vcsa.pass

# Variables to edit
$vROPsServer = "vrops.my.lab"
$vROPSUser = "admin"
$esxihostid = "c08254d8-ca69-490e-8670-c2f696dd1a91"

$esxihostname = "esxi-dell.my.lab"
$vCenterfqdn = "vcsa1.my.lab"
$vCenteraccount = "Administrator@vsphere.local"

# vCenter credentials 
$Passworddecodevcsa = Get-Content vcsa.pass | ConvertTo-SecureString 
$vcsacredential = New-Object System.Management.Automation.PsCredential("$vCenteraccount",$Passworddecode)
$vcsaPassword = $vcsacredential.GetNetworkCredential().Password

# Connect to your vCenter
Connect-VIServer -Server $vCenterfqdn -User $vCenteraccount -Password $vcsaPassword | out-null

# Pull NVMe model/GBW/TBW - thanks - https://www.virten.net/2020/03/how-to-check-nvme-drives-tbw-in-esxi-with-powercli/

Foreach ($vmhost in Get-VMHost -Name $esxihostname ) {
    $esxcli = get-esxcli -V2 -vmhost $vmhost
    $devices = $esxcli.nvme.device.list.Invoke()
    Foreach ($device in $devices) {
        $nvme = $esxcli.nvme.device.get.CreateArgs()
        $nvme.adapter = $device.HBAName
        $Info = "" | Select VMHost, HBA, Model, DataUnitsWritten, GBW, TBW
        $Info.VMHost = $vmhost.Name
        $Info.HBA = $device.HBAName
        $Info.Model = ($esxcli.nvme.device.get.invoke($nvme) | Select-Object ModelNumber).ModelNumber
        $Info.DataUnitsWritten = [int]($esxcli.nvme.device.log.smart.get.Invoke($nvme) |Select-Object DataUnitsWritten).DataUnitsWritten
        $Info.GBW = [math]::round($Info.DataUnitsWritten*512000/1Gb)
        $Info.TBW = [math]::round($Info.DataUnitsWritten*512000/1Tb, 1)
        $AllInfo += $Info
    }
}

# Record NVMe model/GBW/TBW output as Variables for the vROps API POST.
$NVMemodel = $Info.Model
$NVMeGBW = $Info.GBW
$NVMeTBW = $Info.TBW

# Disconnect from the vCenter
Disconnect-VIServer $vCenterfqdn -Confirm:$false

# vROps credentials 
$Passworddecode = Get-Content vrops.pass | ConvertTo-SecureString 
$credential = New-Object System.Management.Automation.PsCredential("$vROPSUser",$Passworddecode)
$vROPsPassword = $credential.GetNetworkCredential().Password

# Powershell API connecton - thanks - https://socialvirtualcloud.com/injecting-data-into-vrops-via-api-from-external-system/
# Defining REST API URLS for use
$BaseURL = "https://" + $vROPsServer + "/suite-api/api/"
$BaseAuthURL = "https://" + $vROPsServer + "/suite-api/api/auth/token/acquire"
$Type = "application/json"

# Creating JSON for Auth Body
$AuthJSON =
        "{
          ""username"": ""$vROPSUser"",
          ""password"": ""$vROPsPassword""
        }"
# Authenticating with API
    Try 
    {
        $vROPSSessionResponse = Invoke-RestMethod -Method POST -Uri $BaseAuthURL -Body $AuthJSON -ContentType $Type
    }
    Catch 
    {
        $_.Exception.ToString()
        $error[0] | Format-List -Force
    }

# Extracting the session ID from the response
    $vROPSSessionHeader = @{"Authorization"="vRealizeOpsToken "+$vROPSSessionResponse.'auth-token'.token
    "Accept"="application/json"}
	
	
# tested via swagger Resource addPropertiesUsingPOST - Add Properties to a Resource along with associating an adapter instance of the specified adapter kind as the source of data
# thanks - https://vman.ch/vrops-custom-network-stats-for-hostsystems/

[xml]$MetricXML = @('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ops:property-contents xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<ops:property-content statKey="NVMe|TBW">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMeTBW+'</ops:values>
    </ops:property-content>
	<ops:property-content statKey="NVMe|GBW">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMeGBW+'</ops:values>
    </ops:property-content>
	<ops:property-content statKey="NVMe|Model">
		<ops:timestamps>1119844280663</ops:timestamps>
        <ops:values>'+$NVMemodel+'</ops:values>
	</ops:property-content>
</ops:property-contents>'
    )


# vROPs POST URL using the esxi host id found in the variables.
$posturl = "$BaseURL/resources/$esxihostid/properties"
 
# One liner to POST into vROps 
Invoke-RestMethod -Method POST -uri $posturl -Body $MetricXML -Headers $vROPSSessionHeader -ContentType "application/xml;charset=utf-8" -TimeoutSec 120
Reading/Testing
ENV/SSL Tip

Setup –
VMware.PowerCLI Version: 12.3.0.17860403
vRealize Operations Manager Version: 8.4.0 (17863947)
vROps has an internal CA signed cert using XCA – https://vmscribble.com/vcenter/vmware-vcsa-use-xca-for-root-and-intermediate-certificate-authority/

If the vROps cert is the out of the box self signed one, you will run into this error:
System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. —> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
Workaround is to add the “using System.Security.Cryptography.X509Certificates;” section to the script from https://michaelryom.dk/vrops-api-consumed-with-powershell/

Tip –
Add to the script to run via the Windows Server Task Scheduler (repeat task every 5 minutes) https://vmscribble.com/powercli/automate-powercli-scripts-via-the-windows-server-2012-task-scheduler/