Based on a snip from William Lam,
Snip here –>
You can use some quick Powershell to:
1 – Download the VPXD.log from your vcenter
2 – Parse that log for
a. API access frequency parsed per API.
b. User Auth frequency parsed per user account.

Why do we care about this?   In my shop, we have an aggressive amount of third party (and VMware tools) that log into vCenter and relentlessly call APIs 24/7/365.  This API usage has pushed some of our vCenters to 20+ vCPUs and 32+GB of memory.  Some well above the “Extra Large” configuration setting at first deployment.  So,  use this script to find out who is logging in, then find out what API calls are being called the most frequent.   If you want, you can go beyond this script and scan vcenter events (with PowerCLI get-vievent) and find the IP address and API method used by the user account you caught with this script.

First, Download and install the WinSCP Powershell commandlets.
If your computer has internet access, run an admin level powershell window and run “Install-Module -name WinSCP”
Help here if needed –>

Second, Make sure your vCenter is ready to accept remote SSH/SCP sessions.
– SSH into your vCenter appliance, switch to the shell prompt with “shell.set –enabled true”  then run “chsh -s /bin/bash root”
— Running this command will force vCenter shell to launch into the bash shell directly and allow remote SCP sessions to work.
— You can manually pull the log if you don’t want to use this command.  Just download the log from vcenter location “/storage/log/vmware/vpxd/vpxd.log” and save it to a local location.  Just keep in mind my script does focus on C:\temp and names the file with the vcenter name using the winSCP method.   Thus, be sure to edit the script as needed if you plan to copy the file from vCenter manually.

Third, edit the top three vars of the script below and paste it into your powershell window.   If you run into any issues, validate the vars, vcenter name, password, your Powershell modules loaded correctly, and that the vCenter SSH Shell is set correctly to allow remote commands.


######  EDIT THESE Vars:
$vcenter = “”
$pass = “VMWare1!”
$yourDomain = “pcli”  #example if domain account is pcli\username1

### Paste The Script
Import-Module winscp
$filename = $vcenter.split(“.”)[0] + “-vpxd.log”
$destinationlocation = “c:\temp\”+$filename
$Cred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList “root”, (ConvertTo-SecureString –String $pass –AsPlainText -Force)
$session = New-WinSCPSession -Credential $cred -Hostname $vcenter -GiveUpSecurityAndAcceptAnySshHostKey
$getfile = Receive-WinSCPItem -WinSCPSession $Session -Path “/storage/log/vmware/vpxd/vpxd.log” -destination $destinationlocation

if($getfile.issuccess -eq $true){
# IF the winSCP session resulted in success,  parse the file
$vpxdLog = Get-Content -Path $destinationlocation
###  find how much data is in the log file and store in var
$date1 = ($vpxdLog | select -f 1).split(” “)[0]
$date2 = ($vpxdLog | select -l 1).split(” “)[0]
$timespanofdata = “{0:N2}” -f (new-timespan $date1 $date2).totalhours

$apiTally = @{}
$userTally = @{}
foreach ($line in $vpxdLog) {
if($line -match “[VpxLRO]” -and $line -match “BEGIN”) {
$field = $line -split ” ”
if($field[13] -match “vim” -or $field[13] -match “vmodl”) {
$apiTally[$field[13]] += 1
}#end IF $field
}#end if $line
if($line -match “User “+$yourDomain+”\\” -or $line -match “User VSPHERE.LOCAL”){
$field = $line -split ” ”
if($field[8] -match $yourDomain){$userTally[$field[8]] += 1}
if($field[8] -match “VSPHERE.LOCAL”){$userTally[$field[8]] += 1}
}#end if $line auth
}#end foreach $vpxdlog

$commandDuration = Measure-Command {
$apiresults = $apiTally.GetEnumerator() | Sort-Object -Property Value | FT -AutoSize @{Name=”vSphereAPI”;e={$_.Name}}, @{Name=”Frequency”; e={$_.Value}}
$userresults = $userTally.GetEnumerator() | Sort-Object -Property Value | FT -AutoSize @{Name=”UserName”;e={$_.Name}}, @{Name=”Frequency”; e={$_.Value}}

$duration = $commandDuration.TotalMinutes
$fileSize = [math]::Round((Get-Item -Path $destinationlocation).Length / 1MB,2)
Write-host “FileName: $destinationlocation”
Write-host “FileSize: $fileSize MB.”
Write-Host “Amount of Logs in file: $timespanofdata Hours.”
Write-host “Time to Parse logfile: $duration minutes.”

Again, Credit to William Lam for the Blog work.  Ping me on twitter @vmnick0 if you have any questions.
And as with all scripts, I know this can be condensed down, but I leave it open to make it easy for others to edit (or take small snips) as needed.

#A quick grep of all VMs in a vcenter, with the configured and running OS (detected by a valid version of VMware tools installed)
#This is a great report if you find out some Admins were running “upgrades” from windows 2008 to 2012 and never reconfigured the VM OS setting.


$temp = get-view -viewtype “virtualmachine” -property name,guest.ToolsRunningStatus,guest.guestfullname,config.guestfullname
$OSMisconfiguredReport = @()
foreach($a in $temp){
$row = “” | select name,toolsstate,OSConfigured, OSRunning
$ = $
$row.toolsstate = $a.guest.ToolsRunningStatus
$row.OSConfigured = $a.config.guestfullname
$row.OSRunning = $a.guest.guestfullname
$OSMisconfiguredReport += $row

$OSMisconfiguredReport | where {$_.toolsstate -eq “guestToolsRunning” -and $_.osrunning -notlike “” -and $_.osconfigured -ne $_.osrunning}


Here is a quick line of code you can throw in to your existing scripts if you want to do some validation based on the type of vcenter.
As more companies are moving to the vCenter appliance, MS Windows issues go away.   Until that time, it’s good to alert on disk space and CPU usage for the Windows vCenter.

The quick one-liner to check the vCenter OS:
if(($global:DefaultVIServer | %{$_.extensiondata.content.about.ostype}) -match “win”){ $windows}else{$Linux}

Here is a Windows vCenter “CPU and Disk space” check script:

$vcenter = “”
$localWindowsAccountUser = “user001”
$localWindowsAccountPass = “test”
## if you want to use a domain account then edit the “$pcstring” var below

Connect-VIServer $vcenter

if(($global:DefaultVIServer | %{$_.extensiondata.content.about.ostype}) -match “win”){
$pcstring = $vcenter+”\”+$localWindowsAccountUser
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $pcstring,(ConvertTo-SecureString -String $localWindowsAccountPass -AsPlainText -Force)
$temp = get-WmiObject win32_logicaldisk -Computername $vcenter -credential $Credential
foreach($b in ($temp | where {$_.drivetype -eq “3”})){
$reportrow = “” | select VMname, DriveLetter, VolumeName,CapacityGB, FreespaceGB,percentFree
$reportrow.vmname = $vcenter
$reportrow.driveletter = $b.DeviceID
$reportrow.VolumeName = $b.VolumeName
$reportrow.capacityGB = “{0:N3}” -f ($b.Size / 1073741824)
$reportrow.freespaceGB = “{0:N3}” -f ($b.FreeSpace / 1073741824)
$reportrow.percentfree = [System.Math]::floor(($b.FreeSpace / $b.Size)*100)
$report += $reportrow
$cpucheck = get-WmiObject win32_processor  -Computername $vcenter -credential $Credential | Measure-Object -property LoadPercentage -Average | Select Average
if(([int]($cpucheck.average)) -ge 90){
$smtpServer = “”
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = “”
$sub = “vCenter HIGH CPU usage found for “+$vcenter
$msg.subject = $sub
$msg.Body = “”
Disconnect-VIServer -Server $global:DefaultVIServers -Force -confirm:$False

You can use this code to send that array data, var output, or CSV file to anyone via email.
Two ways you can do this:

The quick way (no attachments):
– For this you will need a from, to, and valid SMTP server to send the message to.
– To email your script output, just replace the $body var or assign the var to $body.
– $body += $yourscriptdata

$emailFrom = “”
$emailTo = “”
$subject = “Email subject”
$body = “Body of the message”
$smtpServer = “”
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $body)

The detailed way (using attachments)
– I added $thedate var so you can add a date string to your body or subject.
– You can add more files, just add more $fileX parms.
– You can send it to more than one person or group by adding more “$msg.To.Add” lines.

$thedate = (get-date).tostring(‘ddMMMyyy’)
$smtpServer = “”
$file1 = “C:\temp\file1.csv”
$file2 = “C:\temp\vcenterExport.csv”
$att1 = new-object Net.Mail.Attachment($file1)
$att2 = new-object Net.Mail.Attachment($file2)
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = “”
$msg.Subject = “EMail Subject”
$msg.Body = “Body of message – See attached CSV files `n`n`n`n”
sleep 10
del c:\temp\file1.csv
del c:\temp\vcenterExport.csv

*****Its important to run the $attX.Dispose() to free up system memory.

Need to run a quick DNS pull for a list of hosts, VM, vmotion IPs?
Run this, it takes seconds to pull 50+ dns items into a list that you can dump into Excel, csv, etc.

$myDNS = @()
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}
$myDNS += [System.Net.Dns]::GetHostAddresses(“”) | %{$_.IPAddressToString}


OR you can reformat it with a loop + Var if you like using arrays for your host list
$hostname = @()
$hostname += “”
$hostname += “”
$hostname += “”
$hostname += “”

$myDNS = @()
Foreach($singleHost in $Hostname){
$myDNS += [System.Net.Dns]::GetHostAddresses(“$singlehost”) | %{$_.IPAddressToString}