Changing Hyper-V Processor Limit with PoSH

Like many companies today, my company is now using Hyper-V and Microsoft Virtual Server 2008 as a virtual hosting solution. We recently migrated from Virtual Server 2005 to Virtual Server 2008 with Hyper-V.

We quickly learned that when we created or deployed new VM’s they ran terribly slow. After some pondering and thinking back to the original version of Virtual Server, I recalled the resource allocation features. However, I could not find the ability to adjust the resources in the VMM 2008 application; you manage the resource allocation from the Hyper-V manager. We had already discovered that there were things you could do in the VMM that you couldn’t do in the Hyper-V manager and vice-versa. I’m sure this is by design, but what a pain in the [ahem].

Using the Hyper-V manager, I found that the values were set so the virtual machines were all using 12%. I will have to admit, I’ve not had ample time to thoroughly research the “whys” behind this peculiarity. We manage our VMs by setting quota points of 1 per virtual. Each “standard” VM owner is only allowed 1 quota point at a time; each “power” VM owner is allowed 2. This ensures that the VM owners use the VMM Portal managing their own VM’s and keeps too many VM’s from being deployed at once. What we have found is that the popularity and flexibily of VM’s is increasing the number of VM’s being hosted! Setting the resource limit to 100% on all VM’s on a densely populated host is probably not the best idea. But, if they are managed well and VMs are not deployed when not in use, it provides the best performance and encourages the use of VM’s in an organization.

To adjust the resources on a machine to improve performance, we changed the virtual machine limit under the processor settings to 100%. Since we use PowerShell quite regularly in deploying VM’s, installing software to VM’s, as well as other tasks, we tossed around the idea of doing the same to adjust this setting.

After a bit of playing around using get-member and exporing the classes for the virtualization namespace of WMI, I began to piece a simple script together. I found Dung Hoang’s blog quite helpful in speeding up my script creation. Many kudos to Dung Hoang and his great blog on exploring Hyper-V with PoSH. You can find his blog here: http://dungkhoang.spaces.live.com/blog/.

The script below is what I am currently using to change the processor limit. Admittedly, it’s not polished yet. However, it will give you a good idea of what I’m doing with the script.

$HostServer = Read-Host "Enter the Hyper-V Host Server Name"
$VirtualElement = Read-Host "Enter the Virtual Machine Name"</pre>
$VSService = get-wmiobject -computerName $HostServer –namespace root\virtualization –class Msvm_VirtualSystemManagementService
$VM = Get-WmiObject -computerName $HostServer -namespace root\virtualization Msvm_ComputerSystem | where {$_.ElementName -match $VirtualElement}
$VMProcessorSettings = get-wmiobject -computerName $HostServer –namespace root\virtualization –class Msvm_ProcessorSettingData | where {$_.InstanceId -match $VM.Name }
if ($VMProcessorSettings.Limit -ne 100000){
# Set value to maximum
$VMProcessorSettings.Limit = 100000
$VMNewProcessorSetting = $VMProcessorSettings.psbase.GetText()
$result = $VSService.ModifyVirtualSystemResources($VM.__PATH, $VMNewProcessorSetting)
if ($result.ReturnValue -eq 0) {
Write-Host "Success"
} else {
Write-Host "Failure, return code: $result "
}

}
$result.Job
# Error Handling
trap{
Write-Host "ERROR: script execution was terminated.`n" $_.Exception.Message
exit
}
Advertisements

Windows Update Agent with PoSH – Part III

In my last post, I left you hanging with inspecting the PoSH code looking for an error.

Let’s review the code:

#PowerShell script converted from VB Script here: http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx
cls
# Show WUA version
$AgentInfo = new-object -comObject Microsoft.Update.AgentInfo
$WuaVersion = $AgentInfo.GetInfo("ProductVersionString")
Write-Host "Windows Update Manager Version: $WuaVersion"
Write-Host "`n"
# Create session and look for updates applicable to machine where script is run
$updateSession = new-object -comObject Microsoft.Update.Session
$updateSearcher = $updateSession.CreateupdateSearcher()
Write-Host "Searching for updates..."
$searchResult = $updateSearcher.Search("IsInstalled=0 and Type='Software'")
[System.Int32]$Results = $searchResult.Updates.Count
if ($Results -eq 0) {
	Write-Host “There are no applicable updates.”
	return $Results
} else {
	Write-Host “List of applicable items on the machine: $Results”
	Write-Host “——————————————–”
	for ([System.Int32]$i = 0; $i -lt $Results; $i ++ ) {
		$update = $searchResult.Updates.Item($i)
		Write-Host $update.title
	}
}
Write-Host “`n”
# List applicable updates
Write-Host “Creating collection of updates to download:”
$updatesToDownload = New-Object -comObject Microsoft.Update.UpdateColl
for ([System.Int32]$i = 0; $i -lt $Results; $i ++ ) {
	$update = $searchResult.Updates.Item($i)
	Write-Host “Adding - ” $update.title
	$updatesToDownload.Add($update) | Out-Null
}
# Download the applicable updates and list them
Write-Host “Downloading updates…”
$downloader = $updateSession.CreateUpdateDownloader()
$downloader.Updates = $updatesToDownload
$downloader.Download() | Out-Null
Write-Host “`n”
Write-Host “List of downloaded updates:”
for ([System.Int32]$i = 0; $i -lt $Results; $i ++ ) {
	$update = $searchResult.Updates.Item($i)
	if ($update.IsDownloaded){
		Write-Host $update.title ” - is downloaded.”
	}
}
Write-Host “`n”
# Prep for installation
$updatesToInstall = New-Object -comObject Microsoft.Update.UpdateColl
Write-Host “Creating collection of downloaded updates to install:”
for ([System.Int32]$i = 0; $i -lt $Results; $i ++ ) {
	$update = $searchResult.Updates.Item($i)
	if ($update.IsDownloaded){
		Write-Host “Adding - ” $update.title ” - to install list.”
		$updatesToInstall.Add($update) | Out-Null
	}
}
Write-Host “`n”
# Confirm installation. Install if Yes. Exit if No. Exit with message if any other key pressed.
$Response = $(Read-Host “Would you like to install updates now? (Y/N)”)
if(($Response -eq “Yes”) -or ($Response -eq “Y”)){
	Write-Host “Installing updates…`n”
	$installer = $updateSession.CreateUpdateInstaller()
	$installer.Updates = $updatesToInstall
	$installationResult = $installer.Install()
	for ([System.Int32]$i = 0; $i -lt $updatesToInstall.count; $i ++ ) {
		$InstallationResults = $installationResult.GetUpdateResult($i).ResultCode
		Write-Host “Installation Result for: ” $updatesToInstall.Item($i).Title ” - Results:”
		switch ($InstallationResults) {
			0 {Write-Host Red “Installation of Update Not Started”}
			1 {Write-Host “Installation of Update in Progress” }
			2 {Write-Host -foregroundcolor Green “Installation of Update Succeeded”}
			3 {Write-Host -foregroundcolor Yellow “Installation of Update Succeeded with Errors”}
			4 {Write-Host -foregroundcolor Red “Installation of Update Failed”}
			5 {Write-Host -foregroundcolor Red “Installation of Update Aborted”}
		}
		Write-Host “Reboot Required? ” $installationResult.RebootRequired “`n”
	}
	exit
} elseif (($Response -eq “No”) -or ($Response -eq “N”)) {
	exit
} else {
	Write-Host -foregroundcolor Red “`nPlease answer `”[Y]es`” or `”[N]o`” next time!`n”
	exit
}
Write-Host “`n”
# Error Handling
trap{
	Write-Host “ERROR: script execution was terminated.`n” $_.Exception.Message
	break
}</pre>

My question was a bit “leading” I suppose.  There is no error per se.  However, as the script is written, it will list ALL downloads! Do we want ALL updates downloaded and installed? Perhaps not.

We can the script to help with scripted/automated system deployments in a variety of ways (physical as well as virtual deployments).  So, we can improve on this script quite dramatically if we look carefully. There are some optional updates we may not want to install.

First, let’s assume we want to create an automated process for deploying systems. In that case, there’s no need to list the updates; we can eliminate the section which begins:

$updatesToDownload = New-Object -comObject Microsoft.Update.UpdateColl

[We can make the same argument for some other portions of the script such as displaying the WU client version being displayed; that can be removed as well.]

Additionally, if you test this script and compare it against a manual Microsoft Update process by using Internet Explorer, you’ll notice a discrepency in the list generated in PoSH and the one shown by Microsoft Update.  After a bit of research, I found that if you use WSUS in your internal environment, it works quite differently that what expect to see from Microsoft Update.  As I previously mentioned, as this script is written ALL available updates are listed and would be downloaded and installed.

The easiest way around this is to use the AutoSelectOnWebSites property of the IUpdate interface.  In the beginning of the script, we created the session.  If we take advantage of this by narrowing our download selections to only those which would normally be auto-selected by Microsoft Update [we visit the website], then our downloads will be limited to only those “auto selected”.

But, wait!  While we are at it, let’s make sure Windows Firewall is shut down and that we restart the service at the end of the script.

We can also add a reboot option if it is required after an update.

Finally, since this script is intended to be part of an automated deployment process, let’s also create a transcript so we see the results when a reboot is required.

Here is the script. It is what I’m currently use when deploying virtual machines before they are added to our WSUS AD Policy:

function get-datestamp{
	$datestamp = "_" + (get-date).tostring("yyyyMMddHHmmss")
	return $datestamp
}
function get-FWStatus ($ServiceName) {
	# Check Windows Firewall service status, stop if running.
	stop-Service $ServiceName
	Start-Sleep -seconds 5
	Write-Host "Firewall is" $ServiceStatus.status
}
CLS
$ServiceName = "SharedAccess"
$ServiceStatus = get-Service $ServiceName
if ($ServiceStatus.status -eq "Running" -or $ServiceStatus.status -eq "Started"){
	stop-Service $ServiceName
} else {
	do {
		get-FWStatus $ServiceName
	} until ($ServiceStatus.Status -eq "Stopped")
}
$TimeStamp = get-datestamp
$WULog = $env:SystemDrive + "\" + $env:Computername + "_WULog" + $TimeStamp + ".log"
# Create session and look for updates applicable to machine where script is run
Write-Host "Searching for updates...`n"
$updateSession = new-object -comObject Microsoft.Update.Session
$updateSearcher = $updateSession.CreateupdateSearcher()
$searchResult = $updateSearcher.Search("IsInstalled=0 and Type='Software'")
[System.Int32]$Results = $searchResult.Updates.Count
if ($Results -eq 0 -or $Results -eq $null){
	# exit if no updates applicable to this system
	Write-Host "`nNo updates available`n"
	exit
}
# Create collection of items in preparation to download
$UpdatesToDownload = New-Object -comObject Microsoft.Update.UpdateColl
Write-Host "Preparing to download updates...`n"
for ([System.Int32]$i = 0; $i -lt $Results; $i ++ ) {
	$update = $searchResult.Updates.Item($i)
	# Search for updates that are auto selected as critical updates by Microsoft Update Website.
	if ($update.AutoSelectOnWebSites -eq "True"){
		$UpdatesToDownload.Add($update) | Out-Null
	}
}
if ($UpdatesToDownload.Count -gt 0){
	Write-Host "Found" $UpdatesToDownload.Count "updates.`n"
}
else{
	# exit if no updates meet AutoSelectOnWebSites criteria
	Write-Host "`nNo updates available`n"
	exit
}
# Download the applicable updates if collection contains items
Write-Host "Downloading updates...`n"
if ($UpdatesToDownload){
	for ($i = 0; $i -lt $UpdatesToDownload.Count; $i ++ ){
		$downloader = $updateSession.CreateUpdateDownloader()
		$downloader.Updates = $UpdatesToDownload
		$downloader.Download() | Out-Null
		Write-Host $UpdatesToDownload.Item($i).Title " ... has been downloaded."
	}
}
Write-Host "Updates to install:  " $UpdatesToDownload.Count "`n"
# Let's log the actual installation actions and results so we know what the results were
Start-Transcript -path $WULog | Out-Null
# So transcript doesn't get stuck on in case of error, set a flag
$LogStatus = "True"
# Install updates in the collection
Write-Host "Installing updates...`n"
$installer = $updateSession.CreateUpdateInstaller()
$installer.Updates = $UpdatesToDownload
$installationResult = $installer.Install()
for ([System.Int32]$i = 0; $i -lt $UpdatesToDownload.count; $i ++ ) {
	$InstallationResults = $installationResult.GetUpdateResult($i).ResultCode
	switch ($InstallationResults) {
		0 {Write-Host Red "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Update Not Started"}
		1 {Write-Host "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Update in Progress" }
		2 {Write-Host -foregroundcolor Green "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Succeeded"}
		3 {Write-Host -foregroundcolor Yellow "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Succeeded with Errors"}
		4 {Write-Host -foregroundcolor Red "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Update Failed"}
		5 {Write-Host -foregroundcolor Red "Installation Result for: " $UpdatesToDownload.Item($i).Title " - Results: Update Aborted"}
	}
}
#Reboot if necessary
if ($installationResult.RebootRequired){
	Shutdown /r /t 1 /d P:2:4
}else{
	Write-Host "A reboot is not required."
	# Restart Windows Firewall
	Start-Service $ServiceName
}
# make sure to look for transcript flat, stop transcript for normal script exit
if (LogStatus -eq "True"){
	Stop-Transcript
}
# Error Handling - make sure to look for transcript flat, stop transcript during exception catch
trap{
	Write-Host "ERROR: script execution was terminated.`n" $_.Exception.Message
             if ($LogStatus -eq "True"){
		# Restart Windows Firewall
	             Start-Service $ServiceName
                          Stop-Transcript
	}
	exit
}

One thing I’ve noticed, it could be my imagination, but WU appears to run much slower in PowerShell. It could just be my perception.

Linux Distro Review – Qimo 4 Kids

This is a first for me.  I don’t often “endorse” much of anything.  I am of the opinion that there are many tools for most any job.  Whatever computer or operating system you choose, you must select the right tool for you to do the intended job.  However, this is an exception for me.

My daughter attends a small private school.  Funding technology is often a challenge for small schools; this is true even if they are public schools in rural districts.  Resources available as grants are fewer than for a public school due to the nature of a parochial school (or more aptly termed “non-secular”).  Funding technology in a non-secular school can be very challenging.  So, finding anything useful as well as “free” from a monetary standpoint is always a blessing.

Last year, I started out by trying to make a bootable LiveCD of a linux distro that would allow my daughter’s school to use existing licensed (Windows) software while providing a set of useful open source applications such as Open Office.  These were intended to be used in the school’s computer lab.  I quickly ran into hurdles with wine and some of the Windows based applications that were networked.  At the time of my research and testing, I became impressed with two applications:  TuxMath and TuxTyping.

My daughter immediately took to these two applications and needed no encouragement to explore and play with these as well as other linux based games.  Also during this time, I saw the full effects of the school’s current program for reading.  Although there is a sense of competition among all the students for reading and passing comprehension tests for points, it is amazing to see them compete against themselves and taking on the challenges of reading books above their current enrolled class level.

This led me to take on the task of looking for an existing linux distro we could use at home.  I have enough on my hands as it is, I just don’t have time to take on another project.  And, to be bluntly honest, another linux distro might add to the collection of choices but all the world needs is another linux distro (if you get my drift).

I stumbled on Qimo 4 Kids (pronounced “kim-oh”).  Booting is similar to most linux LiveCD’s; unless you have a barnstorming PC, you are going to have to be patient!  The X Windows interface (KDE) is quite friendly.  My 9 year old daughter needed no assistance.  The custom XFCE interface was very intuitive for her and she quickly was off and working on her own with out a bunch of “Daddy how do I …?” or “Daddy, where is …?” or “Daddy, can you help me …?”

For testing, I used my local installation of VMWare running on my laptop with AMD Turion(tm) 64 X2 CPU.  The virtual was configured with 1 – 1.948 GHz CPU, 1GB RAM, sound, no hard drive, no network, no floppy. It boots directly to the Qimo ISO without any problems and the sound works beautifully.

I was happy to see both TuxMath and TuxTyping on Qimo as well as Abiword, EToys, TuxPaint, GCompris, and ChildsPlay.  Although I’m a big fan of Open Office, Abiword is perfect for my daugter as it is a simple word processor.

For younger children, this is fantastic and [currently] fits with my daughter’s age level just fine.  There’s enough variety to keep her busy and it’s all educational.  The XFCE interface keeps the most used programs easily accessible.  The distro isn’t cluttered with a lot of unnecessary items which I like since I’m of the K.I.S.S. frame of mind.

Older students, may not take to the distro. Some of the games and the interface are more visually appealing to those 10 and under in my opinion (especially if you are familiar with GCompris, EToys, and ChildsPlay .  However, TuxMath and TuxTyping can be quite useful for students of any age who need constant drilling in those subjects.  The big plus is the XFCE interface because it keeps it simple.

Qimo has my thumbs up as I think this is ideal for younger students.  The link to Qimo is here:  http://www.qimo4kids.com/default.aspx

Using PowerShell to Assist in Scanning for Conflicker

BEGIN SOAP BOX AND MY ENDORSEMENT FOR GOOD PRACTICES!

Follow these simple guidelines:

http://www.microsoft.com/protect/computer/viruses/worms/prevent.mspx

Make sure you are properly patched, virus scan is up-to-date, passwords are secure, disabling auto-run, etc.  (I recommend staying as up to date as humanly possible.  Check often!)  …. (to use the Seinfeld cliche) yadda, yadda, yadda…

END SOAP BOX!

Ok, let’s use PowerShell to do some scans.

First, download the scs.zip file from:  http://iv.cs.uni-bonn.de/wg/cs/applications/containing-conficker

Unzip the scan tool to a directory.  I used C:\utilities\scs

This is a pretty simple script I came up with this morning.  After spending most of my date at my company making sure that all systems were patched, it was time to make sure we didn’t have something out there.   I use the following script and windows scheduler to periodically scan (again, AFTER ensuring all systems are patched):

# Create a datestamp for files
function get-datestamp{
	$datestamp = "-" + (get-date).tostring("yyyyMMddHHmmss")
	return $datestamp
}
# Create timestamp by date and hour for scheduled scans
$FileTimeStamp = get-datestamp
$SCSScan = "c:\utilities\scs\scs.exe"
$SCSArguments = "c:\utilities\scs\iplist.txt"
$SCSScan $SCSArguments | Out-File "C:\temp\conflicker-scan-Subnet-$FileTimeStamp.txt"

Make sure to edit iplist.txt with your subnet IP addresses. I use SolarWinds to quickly generate an entire subnet address list, copy and past from first host to last, past in text file, save. Then, you can use the iplist.txt as an argument.

Then, all you have to do is set up Windows scheduler.

Use the following command-line for the scheduled task:

%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe C:\scripts\POSH\start-SCSScan.ps1

A /22 subnet took about 10-14 minutes depending on how busy the system was that I ran it on (which was a WinXP SP3 AMD Processor  using 2GB ram; not a workhorse machine by any stretch of the imagination, but just realize that it doesn’t take all that long to run).

So, each time you run this, you will have a time-stamped file noting when then scan began.