Taking Control of VM Sprawl (Part 16)

by [Published on 25 May 2016 / Last Updated on 25 May 2016]

This article continues the discussion of VM sprawl prevention by tallying virtual machine counts across hosts.

If you would like to read the other parts in this article series please go to:

Introduction

As you may recall, my script got a little bit messy in the previous article in this series. The seemingly simple act of tallying VM creation and deletion events across servers resulted in complications related to the restrictions that PowerShell puts on variable usage. Even so, I did come up with a fix. Now its time to integrate that fix into the script that we have been creating. If you haven’t yet read the previous article in this series, or if it has been a while, then I strongly recommend going back and reading it before moving forward with this one.

The Script as it Currently Exists

The code that I provided you in the previous article was designed more to illustrate the concepts that I would be using, rather than to act directly as a part of our script. As such, I wanted to go ahead and give you the script code as it exists right now. Here is the code:

Function Get-MyData($Server){

#Function to get VM log data information

 

Write-Host "The Current Server Name is " -NoNewLine; Write-Host $Server

$MySession = New-PSSession -ComputerName $Server

Invoke-Command -Session $MySession -ScriptBlock {

 

#January 2016

 

$NumJanCreateEvents = ‘0’

$JanCreateEvents = ''

$NumJanDeleteEvents = ‘0’

$JanDeleteEvents = ''

$JanStartDate = ‘01/01/2016 12:00:00 AM’

$JanEndDate = ‘01/30/2016 11:59:59 PM’

$JanCreateEvents = Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13002;StartTime=$JanStartDate;EndTime=$JanEndDate} -ErrorAction 'SilentlyContinue'

$NumJanCreateEvents = $JanCreateEvents.count

$JanDeleteEvents = Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13003;StartTime=$JanStartDate;EndTime=$JanEndDate} -ErrorAction 'SilentlyContinue'

$NumJanDeleteEvents = $JanDeleteEvents.count

Write-Host "In January 2016, there were " -NoNewLine; Write-Host $NumJanCreateEvents -NoNewLine; Write-Host " New virtual machines created."

Write-Host "In the same time period, there were " -NoNewLine; Write-Host $NumJanDeleteEvents -NoNewLine; Write-Host " virtual machines deleted."

 

#February 2016

 

$NumFebCreateEvents = ‘0’

$FebCreateEvents = ''

$NumFebDeleteEvents = ‘0’

$FebDeleteEvents = ''

$FebStartDate = ‘02/01/2016 12:00:00 AM’

$FebEndDate = ‘02/29/2016 11:59:59 PM’

$FebCreateEvents = Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13002;StartTime=$FebStartDate;EndTime=$FebEndDate} -ErrorAction 'SilentlyContinue'

$NumFebCreateEvents = $FebCreateEvents.count

$FebDeleteEvents = Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13003;StartTime=$FebStartDate;EndTime=$FebEndDate} -ErrorAction 'SilentlyContinue'

$NumFebDeleteEvents = $FebDeleteEvents.count

Write-Host "In February 2016, there were " -NoNewLine; Write-Host $NumFebCreateEvents -NoNewLine; Write-Host " New virtual machines created."

Write-Host "In the same time period, there were " -NoNewLine; Write-Host $NumFebDeleteEvents -NoNewLine; Write-Host " virtual machines deleted."

Exit-PSSession

}

}

 

#Script Body

$Servers = @("Hyper-V-1", "Hyper-V-2", "Hyper-V-4", "Prod1", "Prod2")

                ForEach ($Server in $Servers) {

 

$ServerName = $Server

Get-MyData $ServerName

 

                }

Tallying the Results

So now we need to modify the code in a way that allows us to tally the virtual machine creation and deletion events on a per host basis. To do that, we are going to be adopting the techniques that I showed you in the previous article. Let me go ahead and show you the code, and then I will explain what I have done. Here is the code:

Function Get-MyData($Server){

#Function to get VM log data information

 

 

$MySession = New-PSSession -ComputerName $Server

 

#Initialize Variables

Invoke-Command -Session $MySession -ScriptBlock {

 

                #January

 

                $NumJanCreateEvents = ‘0’

                $JanCreateEvents = ''

                $NumJanDeleteEvents = ‘0’

                $JanDeleteEvents = ''

                $JanStartDate = ‘01/01/2016 12:00:00 AM’

                $JanEndDate = ‘01/30/2016 11:59:59 PM’

 

                #February

 

                $NumFebCreateEvents = ‘0’

                $FebCreateEvents = ''

                $NumFebDeleteEvents = ‘0’

                $FebDeleteEvents = ''

                $FebStartDate = ‘02/01/2016 12:00:00 AM’

                $FebEndDate = ‘02/29/2016 11:59:59 PM’

 

                }

 

#January 2016

 

$JanCreateEvents = Invoke-Command -Session $MySession -ScriptBlock {Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13002;StartTime=$JanStartDate;EndTime=$JanEndDate} -ErrorAction 'SilentlyContinue'}

$Global:NumJanCreateEvents = $JanCreateEvents.count

$JanDeleteEvents = Invoke-Command -Session $MySession -ScriptBlock {Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13003;StartTime=$JanStartDate;EndTime=$JanEndDate} -ErrorAction 'SilentlyContinue'}

$Global:NumJanDeleteEvents = $JanDeleteEvents.count

 

#February 2016

 

$FebCreateEvents = Invoke-Command -Session $MySession -ScriptBlock {Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13002;StartTime=$FebStartDate;EndTime=$FebEndDate} -ErrorAction 'SilentlyContinue'}

$Global:NumFebCreateEvents = $FebCreateEvents.count

$FebDeleteEvents = Invoke-Command -Session $MySession -ScriptBlock {Get-WinEvent –FilterHashTable @{LogName=”Microsoft-Windows-Hyper-V-VMMS-Admin”;ID=13003;StartTime=$FebStartDate;EndTime=$FebEndDate} -ErrorAction 'SilentlyContinue'}

$Global:NumFebDeleteEvents = $FebDeleteEvents.count

 

# Monthly Output

 

Write-Host " "

Write-Host "Server: " -NoNewLine; Write-Host $Server

Write-Host "January Create Events: " -NoNewLine; Write-Host $NumJanCreateEvents

Write-Host "January Delete Events: " -NoNewLine; Write-Host $NumJanDeleteEvents

Write-Host "February Create Events: " -NoNewLine; Write-Host $NumFebCreateEvents

Write-Host "February Delete Events: " -NoNewLine; Write-Host $NumFebDeleteEvents

Write-Host " "

}

 

#Script Body

 

#Initialize Variables

$TotalJanCreateEvents = '0'

$TotalJanDeleteEvents = '0'

$TotalFebCreateEvents = '0'

$TotalFebDeleteEvents = '0'

 

 

$Servers = @("Hyper-V-1", "Hyper-V-2", "Hyper-V-4", "Prod1", "Prod2")

                ForEach ($Server in $Servers) {

 

                                $ServerName = $Server

                                Get-MyData $ServerName

                                $TotalJanCreateEvents = [int]$TotalJanCreateEvents + [int]$NumJanCreateEvents

                                $TotalJanDeleteEvents = [int]$TotalJanDeleteEvents + [int]$NumJanDeleteEvents

                                $TotalFebCreateEvents = [int]$TotalFebCreateEvents + [int]$NumFebCreateEvents

                                $TotalFebDeleteEvents = [int]$TotalFebDeleteEvents + [int]$NumFebDeleteEvents

 

                }

Write-Host "Total January Create Events: " -NoNewLine; Write-Host $TotalJanCreateEvents

Write-Host "Total January Delete Events: " -NoNewLine; Write-Host $TotalJanDeleteEvents

Write-Host "Total February Create Events: " -NoNewLine; Write-Host $TotalFebCreateEvents

Write-Host "Total February Delete Events: " -NoNewLine; Write-Host $TotalFebDeleteEvents

At first glance, it would seem that the code has been completely changed. However, the biggest changes are that I shifted a few things around, and I added some new lines that output the values of the variables as the script executes. That way, you can verify that the script is working correctly. Believe it or not, I haven’t done much to the code in terms of functionality.

Before I talk about how the code works, I want to show you what the script’s output looks like. As you can see in Figure A, my script lists the name of each server that it is analyzing, and it lists the number of creation and deletion events for each month. As you will recall, we are currently only examining January and February for the sake of keeping the code short. I will add in other months later on. At the end of the output, the script tallies the total number of creation and deletion events across all servers for each month.

Image
Figure A: Here is the output from my script.

So let’s talk about the code. I’m not going to go into exhaustive detail, because not much has changed. The script body begins by initializing variables that will store the total number of creation and deletion events across all servers for each month. Once these variables have been initialized, I add the names of my servers to the $Servers variable, and then get into the script’s loop.

The loop passes the server names to the Get-MyData function, one by one. The function defines a session to the specified server, and then initializes a number of different variables. These variables are being initialized on the remote server, not on the local system.

After the variables have been initialized, the function begins collecting creation and deletion event information for the specified server. There is a separate collection process for each month. This section works almost exactly as it did before, but I have made two important changes. The commands that assign creation and deletion events to a variable now include the Invoke-Command cmdlet and reference the remote session. This is what makes it possible to assign the data to a variable on the local system.

The other big change is that the variables that count creation and deletion events are now defined as global. That way, the variable contents can be used in the main script block.

When the function returns, the main script body tallies the number of creation and deletion events for each month. The script body uses variables whose names start with $Total for this purpose. These variables were initialized to 0 at the very beginning of the script. Now, the number of creation events is added to the variable, on a server by server basis, until the variable contains the sum total of events across all servers.

Incidentally, you will notice that the lines of code that tally the total creation and deletion events make use of [int]. The [int] tells PowerShell to treat the variable contents as integers. Otherwise, the variable contents are treated as text and are concatenated rather than added together.

Conclusion

We now have a script that tallies virtual machine creation and deletion events across the datacenter. In the next article in the series, we will add in the remaining months and then work on outputting the values to a chart.

If you would like to read the other parts in this article series please go to:

See Also


The Author — Brien M. Posey

Brien M. Posey avatar

Brien Posey is an MCSE and has won the Microsoft MVP award for the last few years. Brien has written well over 4,000 technical articles and written or contributed material to 27 books.