VMware Cloud Community
AGFlora
Enthusiast
Enthusiast

Trouble with populating the Get-VIEventPlus function into html code

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

Reply
0 Kudos
8 Replies
RvdNieuwendijk
Leadership
Leadership

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

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
Reply
0 Kudos
AGFlora
Enthusiast
Enthusiast

Hi RvdNieuwendijk

I could just do that but the format of the html code that I am using is so much nicer.

Thanks for response.

Reply
0 Kudos
RvdNieuwendijk
Leadership
Leadership

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

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

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

Reply
0 Kudos
AGFlora
Enthusiast
Enthusiast

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

Reply
0 Kudos
AGFlora
Enthusiast
Enthusiast

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

Reply
0 Kudos
LucD
Leadership
Leadership

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

Reply
0 Kudos
RvdNieuwendijk
Leadership
Leadership

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.

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
Reply
0 Kudos