VMware Cloud Community
edelldieguez
Contributor
Contributor
Jump to solution

VM-Report Script

Hi Guys,

I got this script and it work well for me all i can do is to find the way to intead of print the report in PCLI console, send it to me by email, here the script:

Get-VM | `
  ForEach-Object {
    $VM = $_
    $VMview = $VM | Get-View
    $VMResourceConfiguration = $VM | Get-VMResourceConfiguration
    $VMHardDisks = $VM | Get-HardDisk
    $HardDisksSizesGB = @()
    $Temp = $VMHardDisks | ForEach-Object { $HardDisksSizesGB += [Math]::Round($_.CapacityKB/1MB) }
    $VmdkSizeGB = ""
    $Temp = $HardDisksSizesGB | ForEach-Object { $VmdkSizeGB += "$_+" }
    $VmdkSizeGB = $VmdkSizeGB.TrimEnd("+")
    $TotalHardDisksSizeGB = 0
    $Temp = $HardDisksSizesGB | ForEach-Object { $TotalHardDisksSizeGB += $_ }
    $Snapshots = $VM | Get-Snapshot
    $Report = "" | Select-Object VMname,ESXname,MemoryGB,vCPUcount,vNICcount,IPaddresses,VmdkSizeGB,TotalVmdkSizeGB,DatastoreName,ToolsVersion,ToolsUpdate,SnapshotCount,GuestOS
    $Report.VMName = $VM.name
    $Report.ESXname = $VM.Host
    $Report.MemoryGB = $VM.MemoryMB/1024
    $Report.vCPUcount = $VM.NumCpu
    $Report.vNICcount = $VM.Guest.Nics.Count
    $Report.IPaddresses = $VM.Guest.IPAddress
    $Report.VmdkSizeGB = $VmdkSizeGB
    $Report.TotalVmdkSizeGB = $TotalHardDisksSizeGB
    $Report.DatastoreName = $VMview.Config.DatastoreUrl
    $Report.ToolsVersion = $VMview.Config.Tools.ToolsVersion
    $Report.ToolsUpdate = $VMview.Guest.ToolsStatus
    $Report.SnapshotCount = (@($VM | Get-Snapshot)).Count
    $Report.GuestOS = $VM.Guest.OSFullName
    Write-Output $Report
  }

Thanks in advance guys.

Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Does your mail server allow smtp connections from any host ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

Reply
0 Kudos
20 Replies
LucD
Leadership
Leadership
Jump to solution

Change your script like this

$report = @()

Get-VM | `
  ForEach-Object {
    $VM = $_
    $VMview = $VM | Get-View
    $VMResourceConfiguration = $VM | Get-VMResourceConfiguration
    $VMHardDisks = $VM | Get-HardDisk
    $HardDisksSizesGB = @()
    $Temp = $VMHardDisks | ForEach-Object { $HardDisksSizesGB += [Math]::Round($_.CapacityKB/1MB) }
    $VmdkSizeGB = ""
    $Temp = $HardDisksSizesGB | ForEach-Object { $VmdkSizeGB += "$_+" }
    $VmdkSizeGB = $VmdkSizeGB.TrimEnd("+")
    $TotalHardDisksSizeGB = 0
    $Temp = $HardDisksSizesGB | ForEach-Object { $TotalHardDisksSizeGB += $_ }
    $Snapshots = $VM | Get-Snapshot
     $Row = "" | Select-Object  VMname,ESXname,MemoryGB,vCPUcount,vNICcount,IPaddresses,VmdkSizeGB,TotalVmdkSizeGB,DatastoreName,ToolsVersion,ToolsUpdate,SnapshotCount,GuestOS
    $Row.VMName = $VM.name
    $Row.ESXname = $VM.Host
    $Row.MemoryGB = $VM.MemoryMB/1024
    $Row.vCPUcount = $VM.NumCpu
    $Row.vNICcount = $VM.Guest.Nics.Count
    $Row.IPaddresses = $VM.Guest.IPAddress
    $Row.VmdkSizeGB = $VmdkSizeGB
    $Row.TotalVmdkSizeGB = $TotalHardDisksSizeGB
    $Row.DatastoreName = $VMview.Config.DatastoreUrl
    $Row.ToolsVersion = $VMview.Config.Tools.ToolsVersion
    $Row.ToolsUpdate = $VMview.Guest.ToolsStatus
    $Row.SnapshotCount = (@($VM | Get-Snapshot)).Count
    $Row.GuestOS = $VM.Guest.OSFullName
    $Report += $Row
  }

$emailFrom = "from@somedomain.com"
$emailTo = "to@somedomain.com"
$subject = "VM Report"
$body = $report | Out-String
$smtpServer = "smtpserver"
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $body)


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

edelldieguez
Contributor
Contributor
Jump to solution

Hi LucD,

Here what i did but i got an error: Exception calling "Send" with 4 arguments: "faliure sending mail"

$report = @()
Get-VM | `
  ForEach-Object {
    $VM = $_
    $VMview = $VM | Get-View
    $VMResourceConfiguration = $VM | Get-VMResourceConfiguration
    $VMHardDisks = $VM | Get-HardDisk
    $HardDisksSizesGB = @()
    $Temp = $VMHardDisks | ForEach-Object { $HardDisksSizesGB += [Math]::Round($_.CapacityKB/1MB) }
    $VmdkSizeGB = ""
    $Temp = $HardDisksSizesGB | ForEach-Object { $VmdkSizeGB += "$_+" }
    $VmdkSizeGB = $VmdkSizeGB.TrimEnd("+")
    $TotalHardDisksSizeGB = 0
    $Temp = $HardDisksSizesGB | ForEach-Object { $TotalHardDisksSizeGB += $_ }
    $Snapshots = $VM | Get-Snapshot
     $Row = "" | Select-Object  VMname,ESXname,MemoryGB,vCPUcount,vNICcount,IPaddresses,VmdkSizeGB,TotalVmdkSizeGB,DatastoreName,ToolsVersion,ToolsUpdate,SnapshotCount,GuestOS
    $Row.VMName = $VM.name
    $Row.ESXname = $VM.VMHost
    $Row.MemoryGB = $VM.MemoryMB/1024
    $Row.vCPUcount = $VM.NumCpu
    $Row.vNICcount = $VM.Guest.Nics.Count
    $Row.IPaddresses = $VM.Guest.IPAddress
    $Row.VmdkSizeGB = $VmdkSizeGB
    $Row.TotalVmdkSizeGB = $TotalHardDisksSizeGB
    $Row.DatastoreName = $VMview.Config.DatastoreUrl
    $Row.ToolsVersion = $VMview.Config.Tools.ToolsVersion
    $Row.ToolsUpdate = $VMview.Guest.ToolsStatus
    $Row.SnapshotCount = (@($VM | Get-Snapshot)).Count
    $Row.GuestOS = $VM.Guest.OSFullName
    $Report += $Row

}

$emailFrom = "vmware.report@mydomain.com.com"
$emailTo = "first.last@mydomain.com"
$subject = "VM Report"
$body = $report | Out-String
$smtpServer = "smtpserver"

$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($emailFrom, $emailTo, $subject, $body)

Reply
0 Kudos
DSTAVERT
Immortal
Immortal
Jump to solution

I see an error in the email address. I noticed because I was about to remove it. I would be very careful publishing any personal information on a public website.

-- David -- VMware Communities Moderator
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Dave is correct, there is indeed an error in the email address (.com.com)

Btw I edited the email addresses.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
edelldieguez
Contributor
Contributor
Jump to solution

Hi Guys,

Thanks for your replies, Just to clarified, that was not a valid email or domain.

Still having an error,

error.JPG

Any Idea??.

Thanks in advance.

Reply
0 Kudos
RvdNieuwendijk
Leadership
Leadership
Jump to solution

Did you change the line:

$smtpServer = "smtpserver"


into something like:

$smtpServer = "mysmtpserver.mydomain.com"


?

Regards, Robert

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
LucD
Leadership
Leadership
Jump to solution

Does your mail server allow smtp connections from any host ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
edelldieguez
Contributor
Contributor
Jump to solution

Hi Guys,

Thanks you guys, now works very nice, all the probem was that i have an extra dot right after the @ in the email address, something like this:

vmware@.vmware.com.

Thanks in advance guys, really appreciate your help.

Reply
0 Kudos
andreasbrunner
Contributor
Contributor
Jump to solution

Hi Luc,

I'm not sure if this is a little bit off topic here.

You are using the  $report = @() very often. The way you  are solving problems is cool by the way

Would it be possible to speed up the collection time if we try to follow James advice?

Link: http://blog.startautomating.com/?tag=/Script-Optimization

Thanks for feedback.

regards

Andreas

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Andreas,

You're absolutely right, the method James shows is a lot faster.

If you creating an array in a bigger vSphere environment you better use the method from the post, it will make a noticable difference in the execution speed of your scripts.

Only drawback, it's more difficult to understand what is going on when someone reads your script.

So for the community posts I'll stick with the old array-style.

Btw that one was a candidate on my list for our PowerCLI Best Practices session at VMworld Smiley Wink

Luc.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
A_S
Enthusiast
Enthusiast
Jump to solution

This suggestion made me curious.

I'm not comfortable with generics and linked lists. But, can anyone (i guess LucD) can give a try by converting this script into one with generics.

I can try this in environment with hig number of VMs.

thanks in advance

A.S.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

There isn't a lot of coding involved to try this out, only change 2 lines.

Change

$report = @()

into

$report = New-Object Collections.Generic.LinkedList[PSObject]

And change

$report += $row

into

$report.AddLast($row) | Out-Null

Note that I added the Out-Null because the AddLast method also sends each $row to the screen.

I'm curious to hear the execution times for this in a big environment.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
A_S
Enthusiast
Enthusiast
Jump to solution

I' trying to avoid using get-vm in big environment (i prefer: get-view -ViewType Virtualmachine -Filter...) but in order to test the differences i used the script from this thread.

see results below and used script.

Thank you for the tip.

regards

A.S.

# Executed against vCenter 4.1/ESX 3.5 hosts/1975 VMs (OSes = Windows 2003/2008/Linux)

# Method 1
# Test with $report = New-Object Collections.Generic.LinkedList[PSObject] ---> $report.AddLast($row) | Out-Null
# elapsed time= 86 minutes

# Method 2
# Test with $report = @() ---> $report += $row
# elapsed time= 104 minutes


$VC=$args[0]

Connect-Viserver $VC

$LogTimeStamp = (Get-Date).ToString("dd-MM-yyyy_hh_mm")
$ScanDateTimeStamp= Get-Date -format "yyyy-MM-dd HH:mm:00.000"

$currDir = Split-path -parent $MyInvocation.MyCommand.Definition
$outputFile = $currDir + "\" + $VC + "_" + $LogTimeStamp + "_VirtualMachine_Inventory.csv"
cls

#Method 1:
$report = New-Object Collections.Generic.LinkedList[PSObject]

# Method 2
# $report = @()

Get-VM | `
  ForEach-Object {
    $VM = $_
    $VMview = $VM | Get-View
    $VMResourceConfiguration = $VM | Get-VMResourceConfiguration
    $VMHardDisks = $VM | Get-HardDisk
    $HardDisksSizesGB = @()
    $Temp = $VMHardDisks | ForEach-Object { $HardDisksSizesGB += [Math]::Round($_.CapacityKB/1MB) }
    $VmdkSizeGB = ""
    $Temp = $HardDisksSizesGB | ForEach-Object { $VmdkSizeGB += "$_+" }
    $VmdkSizeGB = $VmdkSizeGB.TrimEnd("+")
    $TotalHardDisksSizeGB = 0
    $Temp = $HardDisksSizesGB | ForEach-Object { $TotalHardDisksSizeGB += $_ }
    $Snapshots = $VM | Get-Snapshot
    $Row = "" | Select-Object  ScanDateTimeStamp, VMname,ESXname,MemoryGB,vCPUcount,vNICcount,IPaddresses,VmdkSizeGB,TotalVmdkSizeGB,DatastoreName,ToolsVersion,ToolsUpdate,SnapshotCount,GuestOS
    $Row.ScanDateTimeStamp=$ScanDateTimeStamp
    $Row.VMName = $VM.name
    $Row.ESXname = $VM.VMHost
    $Row.MemoryGB = $VM.MemoryMB/1024
    $Row.vCPUcount = $VM.NumCpu
    $Row.vNICcount = $VM.Guest.Nics.Count
    $Row.IPaddresses = $VM.Guest.IPAddress
    $Row.VmdkSizeGB = $VmdkSizeGB
    $Row.TotalVmdkSizeGB = $TotalHardDisksSizeGB
    $Row.DatastoreName = $VMview.Config.DatastoreUrl
    $Row.ToolsVersion = $VMview.Config.Tools.ToolsVersion
    $Row.ToolsUpdate = $VMview.Guest.ToolsStatus
    $Row.SnapshotCount = (@($VM | Get-Snapshot)).Count
    $Row.GuestOS = $VM.Guest.OSFullName

    # Method 1:
    $report.AddLast($row) | Out-Null

    # Method 2:
    # $Report += $Row


}

$report | Export-Csv -path $outputFile -NoTypeInformation -UseCulture


Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Thanks for sharing the results with us.

Looks impressive, nearly 20% faster.

Switching from Get-VM to 'Get-view -ViewType VirtualMachine' would make the script still faster.

For large environments it is indeed advisable to review and think about your scripts.

Btw these are exactly the kind of best practices Alan and me want to show in our VMworld session Smiley Happy


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
andreasbrunner
Contributor
Contributor
Jump to solution

Hi Luc,

I have another offtopic thing regarding reports

This days I watched the following presentations:

Breakout Session WSV406 | Advanced Automation Using Windows PowerShell 2.0 Dan Harman Jefrey Snover
https://channel9.msdn.com/Events/TechEd/NorthAmerica/2011/WSV406
media.ch9.ms/teched/na/2011/ppt/WSV406.pptx

The thing with the Export-ModuleMember was very interesting when building modules

Jonathan Medd PowerShell modules Presentation
https://msmvps.com/blogs/richardsiddaway/archive/2011/05/10/powershell-uk-user-group-may-meeting-sli...

In the last weeks I saw a lot of requests for reports. Would it be a nice idea to present something like a reporting module on PowerCLI Best Practices session at VMworld? :smileycool:

regards

Andreas

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

That's a good suggestion.

But how do you see that practically ?

A module with several reporting scripts as functions in there ?

Or 1 or more general reporting functions that can be parametrised in the call ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
andreasbrunner
Contributor
Contributor
Jump to solution

Hi Luc,

the first choice could reach almost every one here in the forum. Just search the threads, copy all the functions and build the module and call the respective function on demand.

I think about the second choice:

1 or more general reporting functions that can be parametrised in the call ?

Parameterising the call should be the way to go. (At the moment I'm not sure if Alans vcheck function is a good reference for this. In his script you can uncomment necessary options.)

For this reason it might be necessary to analyze the last 15-20 report requests to understand the demands in a general way. This way a few functions would remain:

Let's say something like: one ore more for the host, one for cluster, one or more for vm and the combination between these functions.Depending on the request. This should be the starting point in rebuilding or "transforming" this functions in maby finally 3-4 functions with parameters.

The result should be exported using the export-xls function.

regards

Andreas

Reply
0 Kudos
andreasbrunner
Contributor
Contributor
Jump to solution

Hi Luc,

after I reread your great post this week after several month again I think that a lot can be done or prepared with the new-viproperty property.

Smiley Happy

http://www.lucd.info/2010/07/13/powercli-4-1-brings-the-new-viproperty-cmdlet/

regards

Andreas

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Thanks.

You're right, you can create a set of New-VIProperty definitions, and depending on the report you want, you select a number of these properties.

It will be a lot easier to handle with properties instead of code blocks.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos