Taking Control of VM Sprawl (Part 10)

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

In the previous article in this series, we were working toward building a PowerShell script that would show you who had been creating virtual machines lately. Admittedly, the script isn’t quite ready for general use. There are still a number of issues that we have to address.

As you may recall, our big accomplishment in the last article was translating a user’s SID into a username so that we could figure out who had created a virtual machine. As it stands right now, the script’s output looks something like what you see in Figure A.

Image
Figure A: This is the script’s output as of right now.

In this article, I want to build onto the code that we already have in an effort to extract virtual machine creation events from the event log and put the information into some sort of meaningful format.

Right now we have three separate code blocks that have been created. The first code block counts the number of virtual machines created and the number of virtual machines deleted. That code block is:

$CreateEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13002”}

$DeleteEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13003”}

$CreateEvents.count

$DeleteEvents.count

The second code block displays the virtual machine creation message and the SID of the user who created it. The code that I used for doing so was:

$CreateEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13002”}

$CreateEvents | Select-Object Message, UserID

The third block of code that I have created was the one that reported the names of the users who created virtual machines. This is the block of code whose output I showed you in Figure A. The code that I used to generate that output was:

Get-WinEvent -LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID -EQ “13002”} | ForEach-Object -Process {

$ObjSID = $_.UserID.Value;

$ObjSID

$Object = New-Object System.Security.Principal.SecurityIdentifier ($ObjSID)

$ObjUser = $Object.Translate([System.Security.Principal.NTAccount])

$ObjUser.value

}

So with that said, the first thing that I want to do is to combine these three code blocks into something that gives us a half way meaningful output. Once I have done that, I want to walk you through the code. After that, I will adapt the code to multi-server monitoring and will show you how to use filtering to track virtual machine creation trends. So we have a lot of work ahead of us, but for right now here is the combined script:

CLS

$CreateEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13002”}

$DeleteEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13003”}

Write-Host “There were ” -NoNewLine; Write-Host $CreateEvents.count -NoNewLine; Write-Host ” virtual machines created.”

Write-Host “There were ” -NoNewLine; Write-Host $DeleteEvents.count -NoNewLine; Write-Host ” virtual machines deleted.”

Write-Host ” “

 

$CreateEvents | ForEach-Object -Process {

Write-Host ” “

$ObjSID = $_.UserID.Value;

$Object = New-Object System.Security.Principal.SecurityIdentifier ($ObjSID)

$ObjUser = $Object.Translate([System.Security.Principal.NTAccount])

$_.Message

Write-Host “By: ” -NoNewLine; Write-Host $ObjUser.value

}

Some parts of this script will look familiar to you, and other parts may not. Like I said, my goal wasn’t just to combine the code blocks, but to also turn the output into something meaningful. So let’s talk about how the code works. Here is the code one more time. This time, I have added a line number in front of each line. The code won’t actually run with the line numbers in place, but the line numbers will make it easier for me to explain what is happening. If you want to run the script for yourself, use the code above, not the code below. With that said, here is the script with line numbers added:

  1. CLS
  2. $CreateEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13002”}
  3. $DeleteEvents = Get-WinEvent –LogName Microsoft-Windows-Hyper-V-VMMS-Admin | Where {$_.ID –eq “13003”}
  4. Write-Host “There were ” -NoNewLine; Write-Host $CreateEvents.count -NoNewLine; Write-Host ” virtual machines created.”
  5. Write-Host “There were ” -NoNewLine; Write-Host $DeleteEvents.count -NoNewLine; Write-Host ” virtual machines deleted.”
  6. Write-Host ” “
  7. $CreateEvents | ForEach-Object -Process {
  8. Write-Host ” “
  9. $ObjSID = $_.UserID.Value;
  10. $Object = New-Object System.Security.Principal.SecurityIdentifier ($ObjSID)
  11. $ObjUser = $Object.Translate([System.Security.Principal.NTAccount])
  12. $_.Message
  13. Write-Host “By: ” -NoNewLine; Write-Host $ObjUser.value
  14. }

The first six lines of code display the number of virtual machines created and deleted. Line 1 is simply a clear screen command. This allows us to start with a fresh display each time.

Line 2 captures all of the virtual machine creation events and writes them to a variable called $CreateEvents. Similarly, line 3 captures all of the virtual machine delete events and writes them to a variable called $DeleteEvents.

Lines 4, 5, and 6 use a command that you might not have seen before. This command is called Write-Host. Write-Host simply allows us to print text or the contents of a variable to the screen. So in the case of line 4, we are displaying the text “There were X virtual machines created”. X will be replaced by a numerical value reflecting the total number of virtual machines created. Line 5 does exactly the same thing for the virtual machines that have been deleted. Line 6 simply displays a blank line before we begin displaying the details for the virtual machines that were created.

So as you have probably guessed, lines 7-14 display the virtual machine creation events and their creator. Line 7 references the $CreateEvents variable that we set up in line 2. Remember, this variable contains all of the event log entries referencing virtual machine creations. We are then using the ForEach-Object command to start a loop, which allows us to deal with each of these event log entries individually. The end of line 7 contains the { symbol. Similarly, line 14 contains the } symbol. All of the code that exists between these two symbols is processed by the loop and is therefore repeated for each log entry.

Line 8 inserts a blank line onto the screen and then lines 9, 10, and 11 convert the SID associated with the current log entry into a user name. This username is stored in a variable called $ObjUser. Line 12 displays the message text for the current event log entry. This is the text indicating the name of the virtual machine that was created. Finally, line 13 uses the Write-Host cmdlet and the $ObjUser variable to display the name of the user who created the virtual machine.

In case you are wondering, you can see what the script looks like in action in Figure B.

Image
Figure B: This is what it looks like when I run the script.

Conclusion

This script is a good start, but there is a lot more that we can do. In the next article in this series, I will show you how to run the script against multiple Hyper-V hosts. From there, I want to show you how to filter the output according to date ranges and how to track monthly VM creation trends.

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

About The Author

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top