MED-V – Changing the Workspace Memory pre-deployment

I’ve been working on developing a MED-V workspace for my company.  It’s going to be used to run a single application, and as such, it shouldn’t need much memory.  Some of the systems the workspace will run on will have only 2GB of memory so I don’t want to be using 1GB for the workspace.  I fiddled around for a while trying to find the way to make this change before I started investigating the powershell script in the workspace directory.  If you haven’t run the Workspace Packager yet, this directory won’t exist, but you can copy the commands below into a PS1 and run them yourself.  I would run the Workspace Packager first though so you better understand the options.  In the PS1 file there are a couple of new Med-V specific commandlets used: New-MedvConfiguration,  Export-MedvConfiguration, New-MedvWorkspace, and Export-MedvWorkspace.  Here’swhat my PS1 script looks like (with any company specific info removed, of course!):

Import-module -Name “Microsoft.Medv”

$regFileInfo = New-MedvConfiguration -VmNetworkingMode “BRIDGED” -UxLogonStartEnabled “False” -UxCredentialCacheEnabled “False” -UxRedirectUrls “http://oldsite.mycompany.com” -FtsMode “Attended” -VmMultiUserEnabled “True” -FtsAddUserToAdminGroupEnabled “False” -FtsStartDialogMsg “A virtual environment is being created for application compatibility. The first time setup process can take several minutes to complete.” -FtsFailureDialogMsg “First time setup failed while creating a virtual environment for application compatibility.” -FtsRetryDialogMsg “First time setup failed while creating a virtual environment for application compatibility.” -FtsSetComputerNameEnabled “True” -FtsComputerNameMask “v%hostname%[14]” -FtsSetRegionalSettingsEnabled “True” -FtsSetUserDataEnabled “True” -FtsSetJoinDomainEnabled “True” -FtsSetMachineObjectOUEnabled “True” -VmMemory 512 | Export-MedvConfiguration -Path “C:\Users\heaths\Documents\MyCompany XP VM\MyCompany XP VM.reg” -PassThru

if ($regFileInfo) #If the .Reg file was created, then create the workspace package

{                 New-MedvWorkspace -WorkspaceName “MyCompany XP VM” -VhdFilePath “C:\Users\heaths\AppData\Local\Microsoft\Windows Virtual PC\Virtual Machines\MyCompany XP VM.vhd” -SettingsFilePath “C:\Users\heaths\Documents\MyCompany XP VM\MyCompany XP VM.reg” -VhdRegPath “C:\Program Files\Microsoft Enterprise Desktop Virtualization\MEDV_InternetZoneHighSecurity.reg,C:\Program Files\Microsoft Enterprise Desktop Virtualization\MEDV_RestrictedBrowsingMode_Apply.reg” | Export-MedvWorkspace -Path “C:\Users\heaths\Documents\MyCompany XP VM\MyCompany XP VM.msi” -Overwrite }

OK, that’s a lot of stuff, but let’s look at what’s relevant to this post.  New-MedvConfiguration generates the object that will define your Virtual Machines properties.  Look for -VMMemory.  It’s near the end of the line, but before the Export-MedvConfiguration command.  This setting let’s me change the Virtual Machine’s memoru setting from the default 1024 MB to 512 MB.

So if you are deploying a Med-V Workspace for your company and you’d like to change the default memory setting pre-deployment, that’s how you do it!

UPDATE: I found this blog article that has great info as well.

Collecting Database Information

I mentioned in a previous post that I was going to try and give up my beloved VBScript and work in some more PowerShell.  I’ve been thinking for a while I would make a table to store some information about all the databases that exist across our SQL Servers.  I thought about writing it in VBScript, TSQL, and .NET before settling on PowerShell.  It’s a new language to learn, and while it’s powerful, there is only so much time in the day.  So here it is.  My first full-fledged, ready-for-primetime PowerShell script.
 
First, let’s talk about the script is about.  We need to collect the SQL Server Name, Database Name, SQL version, Database creation date, Data File size, Log File size, and the Database Status.  The easist way to do this is using the .NET classes available through SQL Server Management Objects, known as SMO.
 
The first part of our script loads the SMO namespace and the PowerShell SQL Server Snap-In’s.  At the moment the script only uses Invoke-SQLCmd, but that could be expanded.
 
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
Add-PSSnapin SqlServerCmdletSnapin100
Add-PSSnapin SqlServerProviderSnapin100
 
Next we create an empty array variable called $DBInfo.  In the script I don’t use it yet, but I have played with using ConvertTo-HTML and Out-File to make a simple website.  I have a table (database_info) in a database we use for DBA information (mgmtdb) on one of our servers.  You would need to make a table somewhere of your liking with columns that match our INSERT statement later in the script.
 
$DBInfo = @()
$serverlist = invoke-sqlcmd -serverinstance "yourserver" -query "select distinct(instance_name) from mgmtdb.dbo.database_info"
 
Once we have our list of servers we can begin stepping through it and connecting to each one. We create the $svr variable and connect it to the current server in the loop.  We then populate the $version variable since it won’t change for any database on this server. Then we step through each database that exists on the server using the $svr.databases collection.
 
ForEach ($server in $serverlist)
{
  $svr = New-Object "Microsoft.SqlServer.Management.SMO.Server" $server.instance_name
  $version = $svr.version
  foreach ($db in $svr.databases)
  {

 

At the beginning of each loop we set the value of $dbsize and $logsize as these properties can be empty if the DB is unavailable. We then check the database status before we attempt to get the size properties.  Because the $db.size property includes data and log files we take the sum of the size properties in the $db.logfiles collection and subtract it from the $db.size property.  We also have to divide the log file size by 1024 because it is listed in KB not MB.  Too bad there’s no datafiles collection!

    $dbsize = "NULL"
   $logsize = "NULL"
    If ($db.status -match "Normal")
 {
   $dbsize = $db.size – ($db.logfiles|measure-object -property size -sum).sum / 1024
   $logsize = ($db.logfiles|measure-object -property size -sum).sum / 1024
 }

Now we create some variables for use in our INSERT statement.  the $object.property variables didn’t seem to jive well with all the quotes, so it was easier to set up some base variables.  We also set the date to a SQL datetime friendly format. And remove any commas from the $db.status property as our SQL INSERT statement won’t like those at all!

    $thedate = get-date -format "yyyy-MM-dd hh:mm:ss"
    $svrname = $svr.name
    $dbname = $db.name
    $dbcreatedate = $db.createdate
    $dbstatus = ($db.status).tostring()
    $dbstatus = $dbstatus.Replace(","," ")

 

This next section is kind of meaning less for the script, but it’s wicked fun.  The properties and variables we’ve created can be hard to format for output.  The general PSObject object take care of this delimma for us.  First we create a new object, $obj.  Then we add  each of our different database properties.  Once we are done we add the object to our $DBInfo array.  During each loop a new object is created and added to the array.  You could use "$DBInfo | Format-Table" to more easily view the information, or "$DBInfo | ConvertTo-HTML | Out-File dbinfo.html" to make a quick web page.  If your already have the web server up an automated daily job could overwrite the page so that interested parties can keep track of their database sizes.  We also use this to see if new databases "pop-up" because of a wiley developer!

    $obj = New-Object PSObject
    $obj | Add-Member NoteProperty -name ServerName -value $svr.name
    $obj | Add-Member NoteProperty -name DatabaseName -value $db.name
    $obj | Add-Member NoteProperty -name SQLVersion -value $version
    $obj | Add-Member NoteProperty -name CreateDate -value $db.createdate
    $obj | Add-Member NoteProperty -name DBSize -value $dbsize
    $obj | Add-Member NoteProperty -name LogSize -value $logsize
    $obj | Add-Member NoteProperty -name DBStatus -value $db.status
    $DBInfo+=$obj
 
The final piece is to build your SQL INSERT statement, then use Invoke-SQLCmd to run it.
    $sqlcmd = "INSERT INTO mgmtdb.dbo.SQL_Web_Data VALUES (‘$svrname’,’$dbname’,’$version’,’$dbcreatedate’,$dbsize,$logsize,’$dbstatus’,’$thedate’)"
    invoke-sqlcmd -serverinstance "yourserver" -query $sqlcmd
  }
}
 
I hope this has provided some new insights into PowerShell for anyone who reads this.  I know writing the script (which took about 2 hours with research) taught me a ton of things I’ll use in future PowerSehll scripts, most notably the use of PSObject for formatting and data manipulation.
 
Have a Happy Thanksgiving!

Has Powershell arrived?

I’d have to say yes.  I have been holding out for quite a long time when it comes to Powershell as it really didn’t seem to be taking hold in the marketplace.  I didn’t know anyone who was coding with it or even installing it on their systems.  With Windows 7 and Windows Server 2008 R2 releases looming on the horizon I decided to give it a second look.  The Powershell 2 CTP3 is out, and since I am using Windows 7 RC1, it is preinstalled. 
 
I took a Microsoft Powershell class this week and I am very impressed.  There is a huge reduction in the amount of coding necessary to complete many function, very specifically WMI.  I use WMI for all sorts of tasks and reducing complexity is always good.
 
My pet project right now is to create a script to execute a command against every computer object in a domain and parse the results.  The hard part?  Doing it on 50 systems simultaneously.  The harder part?  Monitoring the commands and starting new jobs as old ones completed.
 
But not with Powershell 2!  New cmdlets Start-Job, Get-Job, and Receive-Job make this a snap!  I am almost done testing a script to automate running ad hoc commands against several hundred systems in a child domain.  My testing has gone very well and right now I am just working on logic to parse the results and determine success or failure.
 
I hope to have the script posted by Tuesday.

PowerShell tip from the MS Scripting Guys

I just read the coolest tip from the MS Scripting Guys.  I haven’t gotten too deep into PowerShell yet as I’ve been very busy with too many other projects, but after reading this I am going to make a bigger effort.  Now I know this is seriously geeky, but I hate the notification options you have in VBScript and the idea of using Balloon Tips in the Notification Area is seriously awesome!  Visit the link below and see how easy it is to add some notification to your own scripts!