Hi everyone,
Here my first post on our blog vBlog.nl. So the first blog is about the VMware DaaS REST API and how the send a mail with a usage report.
I will also provide you the different lines of code for DaaS 7 and 8. For DaaS 8 there is no REST API documentation available and you have to do it with the DaaS 7 version.
Why doing it via the API? In the service center you have the option to download a CSV…
Well normally your sales support colleagues do not have access to the DaaS service center, and the CSV does not contain the friendly names of the tenants. The second thing is that the CSV contains much more information then they need, and in the most cases you will get questions about that 🙂
Download CSV the GUI way:

- Login to your “service center”
- Go to configuration > standard capacity. Here you will find “Download Usage Report”
Lets do it the PowerShell way:
<#
.Synopsis
Get a Daas usage report
.DESCRIPTION
Get a Daas usage report and e-mail it to your colleagues
.EXAMPLE
Get a Daas usage report for DaaS 8
Get-DaasUsageReport -Url -NewCredentials
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
function Get-DaasUsageReport {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false
)]
[ValidateNotNullOrEmpty()]
[string]$Url,
[switch]$NewCredentials
)
begin {
# Validate the input
$uri = $url -as [System.URI]
$UrlValidation = $uri.AbsoluteURI -ne $null -and $uri.Scheme -match 'https' -and $uri.ToString().StartsWith("https://")
If(!$UrlValidation){
Write-Error "Input is not a valid URL, please Try again."
} Else {
break
}
# Trim ending slash
If($url.EndsWith("/")) {
$url = $url.Substring(0,$url.Length-1)
}
#Triyng to store the password ad secure as possible
if($NewCredentials){
if(!(Test-Path 'C:\Temp')){New-Item -Path 'c:\temp' -ItemType:Directory -Force | Out-Null}
$Credential = (Get-Credential -Message "Enter credentials to be safely stored.") | Export-CliXml -Path C:\Temp\MyCredential.xml -Force
}
try{$credential = Import-CliXml -Path C:\Temp\MyCredential.xml} catch {}
if(!$Credential){
$Credential = (Get-Credential -Message "Credentials cannot be found, you deen to add new ones ") | Export-CliXml -Path C:\Temp\MyCredential.xml -Force
}
$domain,$username = $Credential.UserName.Split('\')
$ww = $credential.GetNetworkCredential().password
[xml]$xmlCreds = @"
<DtCredentials type="CREDENTIALS">
<username>$username</username>
<password>$ww</password>
<domain>$domain</domain>
</DtCredentials>
"@
#clear credentials varaiable
$credential = ''
$username = ''
$domain = ''
$ww = ''
# FIX: Invoke-WebRequest : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
# When the portal has no certificate installed
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()
function APIauthentication {
param (
$Daas,
$Body
)
$Headers = @{}
$Headers.Add("Content-Type","application/xml")
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
$creds = Invoke-WebRequest -uri "$url/dt-rest/v100/system/authenticate/credentials" -Body $body -Method Post -Headers $Headers
$Headers.Add("Authorization","$($creds.Headers.Authorization)")
$Headers.Add("x-dt-csrf-header","$($creds.Headers.'x-dt-csrf-header')")
}
. APIauthentication -daas $Url -body $xmlCreds
#clear credentials varaiable
$xmlCreds = ''
}
process {
$RawOrgs = Invoke-WebRequest -Uri "$url/dt-rest/v100/security/manager/organizations" -Method Get -Headers $Headers
$XMLOrgs = [xml]$RawOrgs.Content
$AllOrgNames = $XMLOrgs.List.DtOrganization | ? {$_.disabled -eq $false} | select name,id
$TenantNameHash = @{}
foreach ($org in $AllOrgNames){
$TenantNameHash.Add($org.name,$org.id)
}
$TenantNameHash.Remove("Service Provider")
$RawQuotas = Invoke-WebRequest -Uri "$url/dt-rest/v100/reporting/manager/consumedquota" -Method Get -Headers $Headers
$XMLQuotas = [xml]$RawQuotas.Content
$AllOrgQuotas = $XMLQuotas.list.DtDesktopModelUsageData | select orgid,NumVms,name
$QuotaReport = @()
foreach ($orgQ in $AllOrgQuotas) {
$Tenant = $TenantNameHash.GetEnumerator() | %{$_ | ? {$_.value -eq $orgQ.orgId}}
$hash = New-Object PSObject -property @{Tenant=$Tenant.Key;TenantId=$orgQ.orgId;DesktopModel=$orgQ.name[0];NumVms=$orgQ.numVms}
$QuotaReport += $hash
}
}
end {
$Table = $QuotaReport | ConvertTo-Html | Out-String
#mail body
$MailBody = "
Hi Colleagues,<br>
<br>
Here is th DaaS usage report
<br>
$Table
<br>
<br>
Kind Regards,<br>
The DaaS team
"
# Send the email
$MailCred = (Get-Credential)
$SmtpServer = "smtp.office365.com"
$SmtpPort = 587
$From = $MailCred.UserName
$To = "user@company.ext","user2@company.ext"
$cc = "team@company.ext"
$currentMonth = Get-Date -UFormat %m
$currentMonth = (Get-Culture).DateTimeFormat.GetMonthName($currentMonth)
$Subject = "DaaS usage report $currentMonth"
Send-MailMessage -smtpserver $smtpserver -from $from -to $to -Cc $cc -subject $subject -body $MailBody -BodyAsHtml -Credential $MailCred -Port $SmtpPort -UseSsl
}
}
. Get-DaasUsageReport -Url "https://siteurl.ext" -Verbose
Thanks for this post – used it as basis for my own export to a DWH
Anyone found out what following line in script needs to be changed to after upgrading to DaaS 9 ?
$RawQuotas = Invoke-WebRequest -Uri “$url/dt-rest/v100/reporting/manager/consumedquota” -Method Get -Headers $Headers
Hi Jan,
Actually you need to change more then that… The whole API is changed there because of resource model the use now (I know it is not in the release notes…)
The row “$RawQuotas = Invoke-WebRequest -Uri “$url/dt-rest/v100/reporting/manager/consumedquota” -Method Get -Headers $Headers” and everything under it needs to be changed to something like this:
$custusagereport = Invoke-WebRequest -Uri https://$daas/dt-rest/v100/reporting/manager/custusagereport -Method Get -Headers $Headers
#$custusagereport.Content | Out-File C:\Temp\test.csv
$date = get-date -format yyyyMMdd
$CustReport=@()
foreach($line in $($custusagereport.Content -split “`r`n”)){
$line = $line.split(‘,’)
if($line[8] -match “Basis” -or $line[8] -match “Plus” -or $line[8] -match “Advanced” -or $line[8] -match “RDSH” -or $line[8] -match “Moderate” -or $line[8] -match “Performance” -or $line[8] -match “Power” -or $line[8] -match “Deployed” -or $line[8] -match “Miscellaneous”){
$CustReport += [pscustomobject]@{
#Tenant = $TenantNameHash.GetEnumerator() | %{$_ | ? {$_.value -eq $line[0]}}
Date = $date
ID = ($TenantNameHash.GetEnumerator() | %{$_ | ? {$_.value -match $line[0]}}).Value
Tenant = ($TenantNameHash.GetEnumerator() | %{$_ | ? {$_.value -match $line[0]}}).Key
VDIType = $line[8]
VDICountD8 = $line[9] #Daas8
CPUCount = $line[10] #Daas9
MemCount = $line[12] #Daas9
}
}
}
$MonthToMatch = get-date -format yyyyMM
if((Test-Path “C:\_scripts\TenantVDIQuota$($MonthToMatch).csv”) -eq $false){New-Item -ItemType:File -Path “C:\_scripts\TenantVDIQuota$($MonthToMatch).csv”}
$CustReport | Export-Csv -NoClobber -NoTypeInformation -Path “C:\_scripts\TenantVDIQuota$($MonthToMatch).csv” -Append
Be aware of the if($line[8], this line you need to test very well because this brings back a part of the old api info. So there you need to put your VDI models.
And if you use a custom model, then I do not know the answer yet 😉