Hi
I'm using Luc's Get-VIEventPlus function but having trouble populating my html code: The function works great but what am I doing wrong that the data is not being populated into the html file?
Code:
# Function to perform the work for the data you need
function Get-VIEventPlus {
<#
.SYNOPSIS Returns vSphere events
.DESCRIPTION The function will return vSphere events. With
the available parameters, the execution time can be
improved, compered to the original Get-VIEvent cmdlet.
.NOTES Author: Luc Dekens
.PARAMETER Entity
When specified the function returns events for the
specific vSphere entity.
.PARAMETER EventType
This parameter limits the returned events to those
specified on this parameter.
.PARAMETER Start
The start date of the events to retrieve
.PARAMETER Finish
The end date of the events to retrieve.
.PARAMETER Recurse
A switch indicating if the events for the children of
the Entity will also be returned
.PARAMETER FullMessage
A switch indicating if the full message shall be compiled.
This switch can improve the execution speed if the full
message is not needed.
.EXAMPLE
PS> Get-VIEventPlus -Entity $vm
.EXAMPLE
PS> Get-VIEventPlus -Entity $cluster -Recurse:$true
#>
param(
[VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl[]]$Entity,
[string[]]$EventType,
[DateTime]$Start,
[DateTime]$Finish,
[switch]$Recurse,
[switch]$FullMessage = $false
)
process {
$eventnumber = 100
$events = @()
$eventMgr = Get-View EventManager
$eventFilter = New-Object VMware.Vim.EventFilterSpec
$eventFilter.disableFullMessage = ! $FullMessage
$eventFilter.entity = New-Object VMware.Vim.EventFilterSpecByEntity
$eventFilter.entity.recursion = &{if($Recurse){"all"}else{"self"}}
$eventFilter.eventTypeId = $EventType
if($Start -or $Finish){
$eventFilter.time = New-Object VMware.Vim.EventFilterSpecByTime
$eventFilter.time.beginTime = $Start
$eventFilter.time.endTime = $Finish
}
$entity | %{
$eventFilter.entity.entity = $_.ExtensionData.MoRef
$eventCollector = Get-View ($eventMgr.CreateCollectorForEvents($eventFilter))
$eventsBuffer = $eventCollector.ReadNextEvents($eventnumber)
while($eventsBuffer){
$events += $eventsBuffer
$eventsBuffer = $eventCollector.ReadNextEvents($eventnumber)
}
$eventCollector.DestroyCollector()
}
$events
}
}
$oneMonth = (Get-Date).AddDays(-31)
$entity = Get-Folder -Name datacenters
$events = Get-VIEventPlus -Entity $entity -EventType VmPoweredOnEvent -Recurse -FullMessage
$events | Group-Object -Property {$_.Vm.Name} | %{
$_.Group | Sort-Object -Property CreatedTime -Descending |
Select -First 1 |
where {$_.CreatedTime -lt $oneMonth -and (Get-VM -Name $_.Vm.Name -ErrorAction SilentlyContinue).PowerState -eq "PoweredOff"} |
New-Object -TypeName PSObject -Property @{
VM = $_.VM.Name
LastPoweredOn = $_.CreatedTime
User = $_.VM.Name | Select UserName
Owner = (Get-VM $_.Vm.Name).CustomFields.Item("OwnerDL")
}
writedata $_.VM $_.LastPowredOn $_.User $_.Owner
}
#Function will compile the data passed from the GetCluster Function into HTML table format
##########################################################################################
Function writedata {
param ($VM,$LastPoweredOn,$User,$Owner)
#Write output to html table
###########################
$tableEntry = "<td><font face='Tahoma'>$($VM)</font></td>" +
"<td><font face='Tahoma'>$($LastPoweredOn)</font></td>" +
"<td><font face='Tahoma'>$($User)</font></td>" +
"<td><font face='Tahoma'>$($Owner)</font></td></tr>"
Add-Content $fileName $tableEntry
Write-Host $tableEntry}
End Code:
Thanks
Why don't you use the PowerShell ConvertTo-Html cmdlet to generate the html output? Remove the call to the writedata function from the code and change the line containing the last } into:
} | ConvertTo-Html
There are some things that don't work in your script. One thing is that in PowerShell you have to define a function before you use it. You called the writedata function before it was defined. That does not work.
Something else is that you used properties generated by the New-Object cmdlet as input for the writedata function. However at the location where you called writedata the current object in the pipeline is not the output of the New-Object cmdlet.
Message was edited by: Robert van den Nieuwendijk
I could just do that but the format of the html code that I am using is so much nicer.
Thanks for response.
You can easily enhace the output of the ConvertTo-Html cmdlet by using a cascading stylesheet. via the -CssUri parameter.
For example to use the Tahoma font as in your code you can create a file called html.css that contains:
Body {font-family: Tahoma;}
And then call:
} | ConvertTo-Html -CssUri html.css
Message was edited by: Robert van den Nieuwendijk
Can you try that routine like this ?
$oneMonth = (Get-Date).AddDays(-31)
$entity = Get-Folder -Name datacenters
$events = Get-VIEventPlus -Entity $entity -EventType VmPoweredOnEvent -Recurse -FullMessage
$events | Group-Object -Property {$_.Vm.Name} | %{
$_.Group | Sort-Object -Property CreatedTime -Descending |
Select -First 1 |
where {$_.CreatedTime -lt $oneMonth -and (Get-VM -Name $_.Vm.Name -ErrorAction SilentlyContinue).PowerState -eq "PoweredOff"} | %{
$obj = New-Object -TypeName PSObject -Property @{
VM = $_.VM.Name
LastPoweredOn = $_.CreatedTime
User = $_.VM.Name | Select UserName
Owner = (Get-VM $_.Vm.Name).CustomFields.Item("OwnerDL")
}
writedata $obj.VM $obj.LastPowredOn $obj.User $obj.Owner
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I'm getting the following error:
The term 'writedata' is not recognized as the name of a cmdlet, function, sc
t file, or operable program. Check the spelling of the name, or if a path wa
ncluded, verify that the path is correct and try again.
At D:\VPO\VM\LastPoweredOn\test.ps1:211 char:18
+ writedata <<<< $obj.VM $obj.LastPoweredOn $obj.User $obj.Owner
+ CategoryInfo : ObjectNotFound: (writedata:String) [], Command
tFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Code:
---------
$oneMonth = (Get-Date).AddDays(-31)
$entity = Get-Folder -Name datacenters
$events = Get-VIEventPlus -Entity $entity -EventType
VmPoweredOnEvent -Recurse -FullMessage
$events | Group-Object -Property {$_.Vm.Name} | %{
$_.Group | Sort-Object -Property CreatedTime -Descending |
Select -First 1 |
where {$_.CreatedTime -lt $oneMonth -and (Get-VM -Name
$_.Vm.Name -ErrorAction SilentlyContinue).PowerState -eq
"PoweredOff"} | %{
$obj = New-Object -TypeName PSObject -Property @{
VM = $_.VM.Name
LastPoweredOn = $_.CreatedTime
User = $_.VM.Name | Select UserName
Owner = (Get-VM
$_.Vm.Name).CustomFields.Item("OwnerDL")
}
writedata $obj.VM $obj.LastPoweredOn $obj.User $obj.Owner
}
}
#Function will compile the data passed from the GetCluster
Function into HTML table format
##################################################################
########################
Function writedata {
param ($Obj)
#Write output to html table
###########################
$tableEntry = "<td><font face='Tahoma'>$($Obj.VM)</font></td>"
+
"<td><font
face='Tahoma'>$($Obj.LastPoweredOn)</font></td>" +
"<td><font face='Tahoma'>$($Obj.User)</font></td>" +
"<td><font face='Tahoma'>$($Obj.Owner)</font></td></tr>"
Add-Content $fileName $tableEntry
Write-Host $tableEntry}
#Combine functions into orderly format for the output
#####################################################
writehtmlheader $fileName
writetableheader $fileName
Get-VIEventPlus
writehtmlfooter $fileName
Hi Rob
Do you have any examples?...When I run the code as is I see the html code populated but it doesn't create the file.
Thanks
Try the attached script, but I'm not too sure that your HTML formatting is correct.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You can pipe the output of the ConvertTo-Html cmdlet to the Out-File cmdlet to write the html code to a file. For example:
} | ConvertTo-Html -CssUri html.css | Out-File -FilePath Events.html
About the 'object not found' error when you call the writedata function, as I wrote in my first answer, you have to define the writedata function before you use it. So move the function definition to the beginning of your script. Remember that PowerShell is a shell and not a compiled programming language. You can only use what you have defined before.