Showing posts with label scvmm. Show all posts
Showing posts with label scvmm. Show all posts

Friday, August 1, 2014

WAP Gallery Image, Dynamic IP address, and the SCVMM DHCP switch extension

Recently I had to put together a hands on lab for a number of sales engineers.
The lab involved SCVMM Service Templates, a custom Windows Azure Pack Gallery Image, and a Desired State Configuration module.

I had my environment of Hyper-V 2012 R2, SCVMM 2012 R2, and WAP about 95% configured.  As much as I could and still support the students re-using my VMs with their own Hyper-V Server.

Since the lab was not about WAP, but instead about my gallery image, I wanted to keep it as simple as possible.  I had a cloud, the cloud had a VM Network assigned, the students created a static IP pool.

(I already had an Internal Virtual Switch being created by SCVMM as a Logical Switch so that all lines of dependency were properly drawn)

In the WAP Admin portal - I had the students add the cloud and the VM Network to their plan.

I deploy my Gallery Image, and the domain join failed. 
I look closer, and I see that my VM ended up with an APIPA address and not an address from the IP Pool. 

Come to find out, the default behavior of a WAP Gallery Image is for dynamic IP address assignment. 
Which, if you only ever deploy a gallery image to a Windows Network Virtualization VM Network, you will never notice.  You will instead see that you get an IP from the IP Pool.

Something that I discovered long ago was that there is a custom Hyper-V Virtual Switch extension that ships with SCVMM.  It is actually a DHCP responder.  It catches the IP request, notifies SCVMM, and SCVMM responds with an IP from the SCVMM IP Pool assigned to the VM.  Nifty.

But, this path only happens if the VM is attached to a Windows Network Virtualization (NVGRE) network managed by SCVMM.

Back to the default Gallery Image behavior of a dynamic IP address.  No WNV network, no IP from an IP Pool.  How to fix this?

The only way to fix this is to open the Resource Definition of the Gallery Image, and then open the Network Profile, then the NIC.
And change the AllocationMethod to Static.

While you are in there, you will most likely notice a number of other interesting settings.

But the thing to be aware of is this, these are hard coded values, unless you work through making them settings that are actually exposed to your end customer (at this time you can't expose these settings).
If you change a setting here, that makes a dependency on an SCVMM placement rule, SCVMM will have to find a place that this VM can go to support all of the settings.  If it cannot, your VM will not be deployed.  And your tenant will call.

Wednesday, May 21, 2014

SCVMM is deploying using the wrong VHD or VHDX

I like this one.  It is interesting.
This is a classic case of 'as designed' being exposed through changes in behavior as an implementation evolves.  Combined with what you see in the UI not really being what happens in the system.

I like it because I consider it a bug due to the fact that the behavior has changed between release and applying Update Rollups.

The symptom is this: you deploy a VM (or a bare metal deployment) and you observe that SCVMM is using the incorrect virtual disk.
And you noticed this happening consistently after applying UR2 (IMHO - that is the key differentiator in the behavior change).

In a nutshell - SCVMM is selecting the virtual disk from the Library.  And it is actually getting more than one from the Library and it is using the incorrect one.

Lets back up a bit.  How is SCVMM ending up with an incorrect virtual disk from the Library in the first place.

Objects in the SCVMM Library have this concept of equivalency.  Multiple objects being equivalent to each other, though they are different objects.
And virtual disks are one of these objects.

Lets say that you create one VHD and this is Server 2012 R2, sysprep'd, all ready to go.  You assign that to a Host Profile or a Service Template, or a WAP Gallery Item.  You set the version to 1.0.0.0 and the family to 'Server 2012 R2' and the OS to 'Server 2012 R2 Datacenter'.
You perform some test deployments and all is good, you move ahead and use it.

After a bit, you get new hardware and you create a new VHD.  Identical to the first except you add some additional drivers for the new storage cards and NICs.
You set the version and family and OS the same.

You then open the Host Profile or Service template and select this new disk.
You deploy, and ... your hardware does not work.  Your new device drivers are missing.  You jump up and down and bang your head on the wall.
You run around in circles.

What happened was this.  SCVMM didn't select the single object that you think you selected.  It selected the OS, family, and version.  And it got two back from the Library.  It then used the "first" one, not the second one.  (this is the behavior change - prior to UR2 it was as if the one with the later date was used, but no longer).

Make the version unique (or the family name) and you will fix the problem.

According to the VMM team - this is 'as designed'.  That is developer speak for:  We built it to work that way.
I hope the documentation will soon describe this equivalency concept.  Since it currently mentions it in passing and never really describes anything about it.

Until then, I hope search brings you here.


Thursday, March 27, 2014

Domain join credential formatting for Windows Azure Pack Gallery Items

I normally don’t blog about something that I consider to be a bug, but in this case the failure behavior is difficult to piece together so I thought I would.

Windows Azure Pack Gallery items have the ability to have multiple credentials defined within them.  And these are used for various actions within the application scripts that are defined within the Gallery Item.

There are two credentials are are essentially ‘built in’ – the local administrator and the domain join user.

If you use the VM Role Author – these credentials are defined automatically.  If you spend time playing around with the WAP Tenant API – you will see that these credentials are labeled as ‘intrinsic’ settings on the object.

The local administrator account you cannot avoid – this sets the local administrator password on the VM and it is required by WAP.  The user ‘administrator’ is grayed out, so you have to set the password for the local administrator.

The domain join user is something you cannot avoid if you define that your VM will join a domain.

Your Gallery Item can have additional user credentials as well.  Say a special one that is used to configure an application, or you have a script that adds a user to the local administrators group, or you need to perform some action against a remote SQL Server and need the proper user credentials.

Now – defining user accounts – there are two format options:  domain\username and username@domain.

Well guess what – for the domain join username, you can only use the domain\username format.  If you attempt to use username@domain you will see that the The provisioning of the VM fails. 

The failure message in the SCVMM job log is:

Warning (22044)

One or more virtual machines have failed during customization during the deployment of the service.

Nothing is clear until I look at the unattended.xml that is generated by the SCVMM deployment process to apply to the VM.

The one that works is:

            <Identification>

                <JoinDomain>global.local</JoinDomain>

                <Credentials>

                    <Domain>global</Domain>

                    <Username>administrator</Username>

                    <Password>********</Password>

                </Credentials>

            </Identification>

The one that fails is:

               <JoinDomain>global.local</JoinDomain>

                <Credentials>

                    <Domain xsi:nil="true" />

                    <Username>administrator@global.local</Username>

                    <Password>********</Password>

                </Credentials>

Does this error also apply if a user types the username@domain format in the GUI for the domain join credential when deploying my Gallery Item?  I just tried it – the username@domain format also fails in the GUI. 

Now, I mentioned other credentials – not the ‘special’ credential that is the domain join user.  Can these credentials be defined using username@domain?  Yes, yes they can.  Those credentials can be defined using either format.

Friday, February 28, 2014

SCVMM Service deployment Error (22758) The system cannot find the file specified – but it is right there

I spend days on this issue and did not want to lose the ‘why’ this cost me days.

First, the details of the error:

Error (22753)

The script command with properties: Type (PreInstall), Deployment Order (20) and Parent Type (ApplicationProfile), failed to complete successfully. Refer to the errors list for more information.

Error (22758)

The guest agent encountered an exception while running a script command. Win32ErrorCode: 2147942402 DetailedErrorMessage: The system cannot find the file specified

I can definitively tell you that this error has nothing and something to do with the script being run.  And, this is the SCVMM Agent itself tossing this error, not my script.

First; the most useful log in SCVMM Service Templates is the SCVMM Guest Agent diagnostic log.  You find it buried in the OS of the VM under %ProgramFiles%\<System Center Version>\<VMM Guest Agent Version>\bin\diagnostics\VmmGuestLog.svclog

If you try to open this up with Notepad or WordPad or NotePad++ it just looks like a bunch of poorly formatted XML.  Very difficult to troll through.

However, if you use Microsoft Service Trace Viewer, you have a totally different experience.  Trace Viewer is part of Visual Studio, which you can get an Express version for free, or download it here.

Looking through this I go looking for the events that the SCVMM Job log tossed at me.

I find:

4: GetExpandedGCEErrorInfo reported The script command with properties: Type (PreInstall), Deployment Order (20) and Parent Type (ApplicationProfile), failed to complete successfully. Refer to the errors list for more information.

But not the Win32ErrorCode.

Right after the above is the following:

4: Encountered an exception for ActionItem Type: Gce, Exception: Microsoft.VirtualManager.GuestAgent.Common.GuestAgentException: Error in the application.
   at Microsoft.VirtualManager.GuestAgent.Gce.GceProcessor.GetStdErrorMatch()
   at Microsoft.VirtualManager.GuestAgent.Gce.GceProcessor.PerformPostProcessing(List`1& warnings)
   at Microsoft.VirtualManager.GuestAgent.Gce.GceProcessor.Run(IQueryCancel queryCancel, List`1& warnings)
   at Microsoft.VirtualManager.GuestAgent.AIFactory.GceActionProcessor.ExecuteActionItemSync(Boolean restarting, ActionItem actionItem, IQueryCancel queryCancel, List`1& warnings)
   at Microsoft.VirtualManager.GuestAgent.QueueManager.QueueManager.QueueProcessorThread(Object context)

This definitively tells me that it is not my script, but instead the SCVMM Agent is the one not finding the file. The best that I can determine is that that GetStdErrorMatch() being empty is the root.  But what does a positive return look like?

And, to make it worse, the script ran.  Everything worked!  And if I checked the VM all of the SCVMM artifacts from my Custom Resource were there ( %ProgramData%VirtualMachineManagerData\<one of the temp paths>).  Nothing was missing!

I spent the next few days changing the script, settings for the execution, accounts, paths, different ways to execute it.  It would work sometimes but mostly not.  This was the most frustrating part.  Every now and then I would not get the error; that small glimmer of hope and gets you frustrated and ends up driving you insane.

On the drive home last night the pieces slid together.  This was my log cleanup script.  It was deleting all of the log files that were empty (0kb).  I produce a lot of logs,  this is remote and headless execution, it could be happening anywhere but I have no console to observe anything.  You have to capture every little thing that happens and you don’t want to sort through 26 files when only the 5 with any details actually mean anything.

Not being the one that wrote the code what I am guessing is that; It appears that the output file is created, then fetched, then written back to. And my script deleted it in the middle somewhere.  Simply timing alone, milliseconds, would let it pass.  A moment of a slow disk drive on a hypervisor, possibly.

So, I removed the capturing of the Standard Out and Standard Error and all is good.  Seems like a silly little thing, right?  But again, this is remote installation, if you don’t log it you have no idea what happened.  So turning off logging was actually the very last thing I had any desire to do.

Tuesday, January 28, 2014

Get the scripts for Update Rollup 1 for System Center 2012 R2 VMM

Update Rollup 1 for Virtual Machine Manager 2012 R2 was just released.

There are some annoyances that are fixed in here, so I know lots of folks that will be installing this.

However, one warning – take note of the release notes:

http://support.microsoft.com/kb/2904712

There is a SQL script in there that you must run on your VMM database as a step in the process of applying the Update Rollup.

I anticipate that many folks will get caught by this one, it is just as slick at the error for UR1 of SCVMM 2012 SP1 where it had to be manually uninstalled or else UR2 or later would not apply properly (but it would look like they do).

Considering that SCVMM pushes SQL DAC packs to database servers to build out Services, I am actually really surprised at the need for the additional SQL script.  It seems like these folks should know how to do this without requiring that extra step that can so easily be missed – especially by shops that no longer take the time to read the release notes for each and every update.

So, be aware and get that script.

[update 1/30/14]

My SCVMM Server automatically updated via Windows Update two days ago.

How did I find out?  I tried to deploy a VM from a Service Template and it failed with the error detail that the Host Agent on the target hypervisor was out of date.

Nothing else.

So, I then turned around and ran the SQL script on the VMM 2012 R2 database.

I had no time to learn what the symptom might be from not applying the SQL script.  There has to be one.  Some way to know.

Monday, November 4, 2013

Deploying XenDesktop using the SCVMM Service Template

The latest release of XenDesktop is now available as a Service Template for System Center Virtual Machine Manager.

I am assuming that my blog readers are already familiar with the concept of Service Templates, introduced with SCVMM 2012. 

The “Service” is where the applications and OS are separate entities, they are layered across each other and deployed as a composed entity with intact references and dependencies.  The Template is the representation of these dependencies and relationships.  The Template is ‘deployed’ into a ‘Service’.  The Service is the running machines.

For most of the past year we have been focused on simplifying the deployment of the XenDesktop infrastructure.  After all, there are enough decisions to make without having to spend one or two days installing operating systems, applications, and configuring them.  This is where the XenDesktop VMM Service Template comes in.

The whole idea is to take the monotonous tasks of deploying VMs, installing XenDesktop, configuring those infrastructure machines and reducing them to a few questions and time.  Freeing you up to do more important things.  Ant the end you can have a distributed installation of XenDesktop – the license server, Director, StoreFront, and Controller.  All connected and ready to deliver applications or desktops.

Why not give it a go?

If you just want to see what this is all about, take a look here:  http://www.citrix.com/tv/#videos/9611

If you head over to the XenDesktop download page, you will find a “Betas and TechPreviews” section.  In there you can download the XenDesktop Service Template zip package.  (The Service Template is the TechPreview not the version of XenDesktop).

http://www.citrix.com/downloads/xendesktop/betas-and-tech-previews/system-center-service-template-tech-preview.html

By the way – there are four templates.  One template to install a scaled out XenDesktop, another for an evaluation installation of XenDesktop.  You will also find Provisioning Server templates that can also support scaling out or an evaluation installation.

After downloading the package, unzip it to a convenient location, then open up the SCVMM Console, Select the Library view, and click on the Import button in the ribbon. 

You can always stop here and read the administration guide, it is short and has all the pretty screen shots that this post is missing).

Browse to the XML file in the package you just unzipped. 

Then map your generalized Server 2012 (or Server 2012 R2) VHD / VHDX to the package by selecting the pencil (a red X appears when it is mapped – don’t ask me why a red X)

Just like the generalized virtual disk, if you want SCVMM integration enabled, then place the SCVMM installation ISO in your VMM Library and select that pencil icon to create the mapping.

The Custom Resource should be uploaded from the package and contains the Citrix parts.

There is a really short import video here if you don’t want to read all of that.

After you import, you can deploy the XenDesktop infrastructure by simply right clicking the template and selecting Configure Deployment.  Answer a few pertinent questions, select Refresh Preview for SCVMM to place the machines, and select Deploy Service.  The name you give your Service will also become the name of your XenDesktop Site.

Now, go to lunch.  When you return, connect to the console of the Controller VM, open Studio, and begin publishing desktops.

You can watch a shortened version of the deployment process.

The requirements are not different than any version of XenDesktop.  There needs to be; a domain to join with DNS, a SQL Server, a VM Network from which the machines can reach those resources, a RunAs account for the (first) XenDesktop administrator, and a user account for XenDesktop to integrate with SCVMM.

As time passes you may decide that you need additional StoreFront Servers or Desktop Controller servers.  To do that, select your Service in the VMs and Services view, right click, and Scale Out.  Select the tier and go.  Additional Controller capacity is created for you and added to the Site, StoreFront requires some additional configuration so you can tailor the load balancing to your environment.

If you need to see that one, I have a video for that as well.

If you need support, you can get that in the XenDesktop forums, we will be there to help and respond to questions.

Please, give us feedback and let us know what you think.

Friday, October 25, 2013

SCVMM Service deployment and NO_PARAM server: NO_PARAM: NO_PARAM

I have to say.  This particular error is my favorite of all time (so far).

Here is the scenario:

  • I deploy a Service form a Template.
  • I wait.
  • The Job fails.
  • I check the SCVMM Job log and see something resembling this:

Error (2912)

An internal error has occurred trying to contact the NO_PARAM server: NO_PARAM: NO_PARAM.

NO_PARAM

Recommended Action

Check that WS-Management service is installed and running on server NO_PARAM. For more information use the command "winrm helpmsg hresult". If NO_PARAM is a host/library/update server or a PXE server role then ensure that VMM agent is installed and running.

Error (20400)

1 parallel subtasks failed during execution.

Error (2912)

An internal error has occurred trying to contact the NO_PARAM server: NO_PARAM: NO_PARAM.

NO_PARAM

Recommended Action

Check that WS-Management service is installed and running on server NO_PARAM. For more information use the command "winrm helpmsg hresult". If NO_PARAM is a host/library/update server or a PXE server role then ensure that VMM agent is installed and running.

Error (20400)

1 parallel subtasks failed during execution.

 

I can tell you from experience that this error has absolutely nothing to do with WinRM.  In fact, if you spend time there, it is wasted.

So, what happened?

In a nutshell; your script / installer ran, and it did not throw a single error.  Not one.  But, your timeout setting was too low due to something, anything and SCVMM gave up waiting for the Exit Code 0 that your script had finished.

Recall, that there was no error, so SCVMM did not have one to pass back up the chain to you and put in the job log.  That is where all of this NO_PARAM business is coming from.  Literally, no error was passed to something as a parameter and that particular piece of code is simply stating that it didn’t receive one.

And SCVMM reports this error as an error and pattern matches it and attempts to give you some guidance around it – where the WinRM part comes from.

 

I first caused this to happen because my script was stalled with a dialog box that was open, waiting for someone to respond, and since everything you define in your Service Template runs headless, there is no way to even know the dialog appeared – other than to logon to your VM and see that the script process continues to run.

I have also seen this happen again when there is high disk IO causing the various installers or configuration scripts to actually run slower.

Just to give a few clues as to why you see this in the first place, as it is a real mystery until you figure it out.  It took me a couple weeks to sort it all out.  Now, I avoid it – I spread my VMs across my hosts by selection.

Friday, October 4, 2013

Scripted installation of the SCVMM Console

This actually seems like it would be pretty straightforward.  However, a documentation bug leaving out a critical switch leaves you guessing.

The following runs on a VM where the the SCVMM ISO is attached.  Nothing more needs to be done beyond attaching the ISO to the VM and executing the script.  This is essentially totally hands-off.

The thing you will probably want to pay attention to are the command line switches for the Console installer.

# CD-ROM selects anything in the DVD drive.  The size ensures that something is mounted.
$dvdDrives = Get-Volume | where {$_.DriveType -eq "CD-ROM" -and $_.Size -gt 0}
# Since a VM could have more than one DVD drive, and SCVMM might be using one for its own purposes we need to find the correct one.
foreach ($dvd in $dvdDrives){
    #test for the sample INI file in the right location to ensure this is the VMM media.
    Switch ([System.IntPtr]::Size)
    {
        4 {
            If (Test-Path -Path ($dvd.DriveLetter + ":\i386\") -PathType Container){
                $vmmMedia = Get-ChildItem -Path ($dvd.DriveLetter + ":\i386\Setup\") -recurse -Filter "VMClient.ini"
            }
        }
        8 {
            If (Test-Path -Path ($dvd.DriveLetter + ":\amd64\") -PathType Container){
                $vmmMedia = Get-ChildItem -Path ($dvd.DriveLetter + ":\amd64\Setup\") -recurse -Filter "VMClient.ini"
            }    
        }
    }
    If ($vmmMedia -ne $null){
        If (Test-Path $vmmMedia.FullName){
            $FilePath = (Get-ChildItem -Path $vmmMedia.PSDrive.Root -Filter "Setup.exe").FullName
        }
    }
}
if ($FilePath) {
    try {
        "Starting SCVMM Console installation."
        Get-Date -Format HH:mm:ss
        Start-Process -FilePath $FilePath -ArgumentList "/client /i /IACCEPTSCEULA" -Wait -NoNewWindow
        "Done waiting for the installer"
        Get-Date -Format HH:mm:ss
        Start-sleep 30
        "SCVMM Console installed."
        Get-Date -Format HH:mm:ss
    }
    catch {
        $Error |  Out-File $logFile -Append
    }
}
else{ Write-Error -Category ObjectNotFound -Message "The SCVMM Installation media was not detected." -RecommendedAction "Please manually install the SCVMM Console" }

Thursday, September 12, 2013

PowerShell to enable Remote Desktop for Administration on the local machine

I had a teammate request that I enable Remote Desktop for Administration as a portion of my SCVMM Service Template.

You cannot script sconfig – although that is a easy manual way to do it.

If you try any of the Server 2012 cmdlets you will end up mucking with Remote Desktop Services and enabling user access.

Well, it turns out the key is a key.  And it is easiest to tweak it with WMI.

The following script runs on the server that is being modified (localhost is the default).  And it can run using administrator or local system security credentials.

try {
    $RDP = Get-WmiObject -Class Win32_TerminalServiceSetting `
                        -Namespace root\CIMV2\TerminalServices
                        # -Computer $Computer `
                        # -Authentication 6 `
                        # -ErrorAction Stop
} catch {
    "WMIQueryFailed"
    continue
}
if($RDP.AllowTSConnections -eq 1) {
    "RDP Already Enabled"
    continue
} else {
    try {
        $result = $RDP.SetAllowTsConnections(1,1)
        if($result.ReturnValue -eq 0) { "Enabled RDP Successfully" }
        if ($result.ReturnValue -eq 4096) {
                $Job = [WMI]$Result.Job
                while ($Job.JobState -eq 4) {
                    Write-Progress -Id 2 -ParentId 1 $Job.Caption -Status "Executing" -PercentComplete $Job.PercentComplete
                    Start-Sleep 1
                    $Job.PSBase.Get()
                }
        }
    } catch {
        "Failed to enable RDP"
    }
}

Thursday, July 25, 2013

SCVMM UR3 causes VMM Service to crash on Placement

I am sharing this because it burned me, and why should it burn anyone else.

This should have the sub-title of: “you need to read the release KB articles in deep detail” or “just don’t install Update Rollup 1 in the first place and you will be happier”.

I recently jumped straight into Update Rollup 3 for SCVMM 2012 SP1.  Because I had reported some bugs and the fixes were in there.

So, I downloaded the update rollup and I applied it to my VMM Console and to my VMM Server.

I then pushed out new agents to my remote Library Server and my Hyper-V Servers.  All was good.  Or so I thought.

I then deployed a Service Template.

During the time when SCVMM was sorting out where to place the VMs in my Service the VMM Service crashed.  Okay, so I tried again.  (not to expect a different result but to pay attention to figure out what was going wrong).

In the event log of the SCVMM Server I found the following message:

Log Name:      Application

Source:        Windows Error Reporting

Date:          7/24/2013 12:15:47 PM

Event ID:      1001

Task Category: None

Level:         Information

Keywords:      Classic

User:          N/A

Computer:      beSCVMM.brianeh.local

Description:

Fault bucket , type 0

Event Name: VMM20

Response: Not available

Cab Id: 0

Problem signature:

P1: vmmservice

P2: 3.1.6018.0

P3: Engine.Placement

P4: 3.1.6027.0

P5: M.V.E.P.C.VMDCConversionHelper.GetVMDCPrecheckResources

P6: System.MissingMethodException

P7: bf35

P8:

P9:

P10:

These files may be available here:

Analysis symbol:

Rechecking for solution: 0

Report Id: 711cf4e8-f495-11e2-9404-00155d289b00

Report Status: 262144

Hashed bucket:

Event Xml:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">

  <System>

    <Provider Name="Windows Error Reporting" />

    <EventID Qualifiers="0">1001</EventID>

    <Level>4</Level>

    <Task>0</Task>

    <Keywords>0x80000000000000</Keywords>

    <TimeCreated SystemTime="2013-07-24T19:15:47.000000000Z" />

    <EventRecordID>5184</EventRecordID>

    <Channel>Application</Channel>

    <Computer>beSCVMM.brianeh.local</Computer>

    <Security />

  </System>

  <EventData>

    <Data>

    </Data>

    <Data>0</Data>

    <Data>VMM20</Data>

    <Data>Not available</Data>

    <Data>0</Data>

    <Data>vmmservice</Data>

    <Data>3.1.6018.0</Data>

    <Data>Engine.Placement</Data>

    <Data>3.1.6027.0</Data>

    <Data>M.V.E.P.C.VMDCConversionHelper.GetVMDCPrecheckResources</Data>

    <Data>System.MissingMethodException</Data>

    <Data>bf35</Data>

  </EventData>

</Event>

So, I removed UR3 (the VMM Server KB…510).  I removed the hosts and remote library server from vmm management and added them back.  I fixed up all of my templates (Export them and Import them do fix them quickly).

I opened a case.

In the end, what was the root problem?   I didn’t uninstall Update Rollup 1.

Seriously?

Come to find out, buried in the details of this KB: http://support.microsoft.com/kb/2802159 is the installation information that Update Rollup 1 for SCVMM should be uninstalled manually prior to installing Update Rollup 2 (or any following Update Rollup).

Personally, I never read that particular article prior to installing UR2.  So I never knew to install UR1.  And, it is highly unusual to have to manually uninstall an Update Rollup prior to adding a second.

So, I then uninstalled UR1.  I re-applied UR2.  Then I installed UR3.  And all was happy.

Now, one easy way to check for this: 

If you select About from the ribbon of the SCVMM console you will see a version.  If you have UR3 installed it should be 3.1.6027.0 

If you have UR2 installed it should be 3.1.6020.0 

If you never manually uninstalled UR1 it will remain at 3.1.6018.0 after applying UR2 or UR3.

The forgotten BIN element in Hyper-V Storage planning

This is an issue that VDI deployments always run in to.

The symptom is this:  I deployed bunches of VDI VMs.  Folks begin using them.  And a week goes by.  Suddenly I notice that most all the reserve storage that I had planned on is gone. 

I don’t have any snapshots happening.  I check that the backup software isn’t leaving weird VSS backups or temporary files lying around.  I even look for AVHDs (though I know there should not be any).

So what happened?

I go looking around and I see all these .BIN and .VSV files.

The VSV is a small placeholder.

However, the BIN is equal in size to the amount of RAM that the running VM is consuming.  If you have Dynamic Memory enabled, it equals the amount of Assigned Memory – so it changes.

Therefore, Dynamic Memory on, means that you design for the worst case scenario – calculate for the Maximum Memory setting of all the VMs stored on that particular LUN.

What this will cause you to do is:

  1. Realize the impact that this BIN file has on storage.
  2. Be smart about setting the Maximum Memory of your VMs.
  3. Understand the risk and accept the risk and push forward without making any considerations.

If you have read this far you might be thinking, What is this BIN file for anyway?

It is a safety net for your VM(s).

It is a placeholder that reserves storage on the file system, so that if the hypervisor needs to reboot, it can quickly dump the memory of your VM(s) to disk.

This does not help you if the hypervisor crashes due to something like a bad driver, this is Hyper-V being able to respond to something and save your VMs – Oh, such as when you run out of storage and it puts your VMs into a saved state.  That is one use.

Wednesday, July 24, 2013

Turn off SCVMM console auto logon

I am sure that everyone at some time has checked that little box on the SCVMM console during the prompt for credentials “Automatically connect with these settings”

image

Only at some time in the future to want to turn that off.

Well, it surely isn’t obvious how to uncheck that box. 

If you are super fast and you capture the window and attempt to click it, you will discover that the opportunity never exists.  It is grayed out, blocked.

If you go looking for ini files or .config files you will come up dry.  Anything in the user profile, again you are dry.

So, what is left?  The registry.

Here it is:

Under HKEY_CURRENT_USER\Software\Microsoft\Microsoft System Center Virtual Machine Manager Administrator Console\Settings\Shared in the registry you will find “autoConnect”

Simply modify that from “True” to “False” and you will once again be prompted for credentials.

Because who wants to logout and on to Windows as different users all the time just to act as different RBAC roles in SCVMM?

Not I.

And what if I want to have multiple consoles open, each as a different user.  I need to uncheck that for that case as well.

Monday, June 24, 2013

Passing and parsing @ServiceVMComputerNames@

In my past post I mentioned the undocumented Service Settings that SCVMM will automatically fill-in for you and pass to your Application Scripts.

But, how can we pass these?

Some are easy, you just pass them like any other setting since they are relatively short strings.

For example, in testing things for this article I passed @ServiceVMComputerNames@, @ComputerName@, @ServiceName@, @VMID@, and @ServiceID@.  I had no idea how long these might be or what they might look like.

My Test Service had two tiers.  One tier with two VMs, one tier with one VM.  It looks like this:

image

When I deployed the Service I named it “blah”, I have a tier named “The Tier” and another named “The Other Tier”, and three VMs named “xVM01”, “xVM02”, and “yVM01” (SCVMM applied the numbers using the ## notation). 

Within VM xVM01 I sent and captured all of the settings I have mentioned.

What I got out was:

  • @ServiceVMComputerNames@ = “The Tier[xVM01,xVM02]The Other Tier[yVM01]”
  • @ComputerName@ = “xVM01”
  • @ServiceName@ = “blah”
  • @VMID@ = “26fd4a55-a707-4fba-89b5-c6955e4e05a2”
  • @ServiceID@ = “741fbf99-e676-4a8b-9df7-096c0be1fd3e”

These short service names you can safely pass using:  myscript.ps1 –paramName @VMID@ or myscrpt.cmd @VMID@

There are lots of examples about that.

It is @ServiceVMComputerNames@ that could get really long and in turn make the command line too long to execute.  So, this one I pass in a bit differently.  To accommodate the length I pipe the setting to my PowerShell script (as I blogged about here).

In the Service Template designer this looks like:

image

My script receives the object as a pipeline and writes it out.

Within the script:

Param
(
    [parameter(Mandatory = $false, ValueFromPipeline = $true)]
    $serviceNames = ""
)

$logPath = "$env:ProgramData\testPath\"
# write out the string for debugging
$serviceNames | Out-File ($logPath + $startTime.Second + $startTime.Millisecond + ".txt")

Then I can just keep reusing this snip to see what I end up with.

What I in turn do with this input is I parse it into an XML document that I later re-use with other SCVMM Application Scripts.

Param
(
    [parameter(Mandatory = $false, ValueFromPipeline = $true)]
    $serviceNames = ""
)

$logPath = "$env:ProgramData\MyService\"

# make the path so Out-File will be happy
If (!(Test-Path -Path $logPath -PathType Container)){
    New-Item -Path $logPath -ItemType Container -Force
    Start-Sleep 10  # so the OS can register the path
}

# Parse the Service information from SCVMM
$tiers = $serviceNames.Split(']')

$service = New-Object System.Xml.XmlDocument
$root = $service.CreateElement("ServiceTemplate")
$root.SetAttribute("version","1.0")
$root.SetAttribute("createon",(Get-Date))
$root.SetAttribute("createdby","brianeh")

foreach($tierString in $tiers) {

    if($tierString){  #ignore any empties
        $tier = $service.CreateElement("Tier")

        $e = $tierString.Split('[')

            $tier.SetAttribute("Name",$e[0])

            $VMs = $e[1].Split(",")

            foreach ($vmString in $VMs){
                if($vmString){
                     $vm = $service.CreateElement("VM")
                     $vm.SetAttribute("Name",$vmString)
                 }
                $tier.AppendChild($vm)
            }

    }
    $root.AppendChild($tier)
}
$service.AppendChild($root)

$service.Save(($logPath + "ServiceNames.xml"))

There you have it, nice and neat XML.  And your scripts have a clue about themselves.

Friday, June 21, 2013

SCVMM hidden system Service Settings

Lately I have been spending a great deal of time with the System Center Virtual Machine Manger Service model and building Service Templates.

Just understanding what the Service model is, and how it takes the SCVMM VM composition model and brings it up to the enterprise / distributed application level helps you understand where MSFT is headed.  To continue this evolution, take a look at the v1 of Desired State Configuration that has been announced in Server 2012 R2.  But that was a bit off topic.

In the title I mention “system” Service Settings.

If you have spent any time with building SCVMM Service Templates you know that you can define many settings by using the “@MySetting@” notation.  When you deploy your Template and it becomes a running Service whomever is deploying is prompted to fill in the Settings you have defined.

This is excellent, now I have the ability to build a template, give it to you and you can personalize it for your environment.  I have one example back here where I built a template for the first domain controller in a domain.

Now, that is all fine and dandy. But what if you need to know ‘something’ about all the other Tiers in the Service.  Such as; “who are the machines in Tier Q?”  Why; '”Because I need to configure an application on this machine to talk to them.”

Before going farther, understand what when SCVMM executes the application scripts in a Service Template as it is being deployed, the scripts within a single machine all run inside the bubble of that machine.  They only know about themselves.  But most enterprise applications need to know about something other than them.  These are big, scaled-out, distributed applications with multiple server roles that all need to talk to each other.

Well, this is where (courtesy of a MSFT PM, who gave approval for me to write this) I ran across some undocumented Service Settings.  These are Service settings that SCVMM fills in during the “Refresh Preview,” instead of prompting your customer; and will process during the deployment.

In my last post I wrote about turning a string into XML.  My sample string was from the Service Setting; @ServiceVMComputerNames@.

  • @ServiceVMComputerNames@ – Each Tier in the Service and the ComputerName within them.  In my mind, this is the handiest.  And you can get very similar information from the Azure Service.Runtime within a PaaS VM.

This gives you a string with the name of each Tier in your Service and the ComputerNames within it.  It is handy information.  In the follow-up post I will give my entire solution to passing and parsing this.

Other system Service settings that SCVMM can directly pass include: 

  • @ComputerName@ – the computer name assigned to the VM.
  • @ServiceName@ – the name of the deployed Service the VM is a member of
  • @VMID@ – the GUID of the VM in SCVMM
  • @ServiceID@ – the GUID of the Service in SCVMM

There may be more.  As far as I can tell, these are not documented at this time.  And it takes a bit of work to discover them and the formatting.

Thursday, June 13, 2013

Turning a string into an XML document with PowerShell

This is one of those things that always seems like it should be really easy, and straightforward.

Well, if you are deeply familiar with XML it might be.  And If you can pry your string apart into an array using split or regex you have half of the problem tackled.

Lets begin by looking at my string.

$s = "Machine Tier - ScaleOut[Machine03,Machine04,Machine05]Machine Tier[Machine02]"

Ugly thing.  That actually contains three elements of data.

The entire string represents a Service.  The data outside the brackets represents a Tier.  The data inside the brackets is a list of VMs in that Tier.

First, I need to break it all apart.

$a = $s.Split(']');
foreach($b in $a) {
    $c = $b.Split('[');
    "Tier = " + $c[0];
    "VMs = " + $c[1];
}

Tier = Machine Tier - ScaleOut
VMs = Machine03,Machine04,Machine05
Tier = Machine Tier
VMs = Machine02
Tier =
VMs =

Okay, that is close, but not quite there. And still not usable.

First, lets do something about that empty last item in the array.

$a = $s.Split(']');
foreach($b in $a) {
    if($b){
        $c = $b.Split('[');
        "Tier = " + $c[0];
        "VMs = " + $c[1];
    }
}

And now, break apart the VM name string

$a = $s.Split(']');
foreach($b in $a) {
    if($b){
        $c = $b.Split('[');
        "Tier = " + $c[0];
        $VMs = $c[1].Split(",")
        foreach ($vm in $VMs){
            "VM = " + $vm
        }
    }
}

Tier = Machine Tier - ScaleOut
VM = Machine03
VM = Machine04
VM = Machine05
Tier = Machine Tier
VM = Machine02

Okay, now I have something that is usable.  And now I want to turn that into XML.

I have spent a great deal of time searching on PowerShell and XML.  Trying to figure out how to build an XML using PowerShell on the fly in my script.  All the examples always start with a TXT based framework of some type that is in turn manipulated by the author.  Or a file is read, or objects are queried.

I am sorry, but this is not an example of generating an XML using PowerShell as the title suggests.  It is a huge formatted text object that is manipulated.  Such a frustrating example to hit over and over again.

Well, I just have this silly string I parsed apart.  And I want that to be XML.  It already has meaning to the pieces, I just need to make them tags and whatnot.

I mentioned early on that I don’t know much about XML.  I read it, transpose it, consume the XML of others’, I never made my own.  So, I had to visit the wisdom of a developer friend and make sure that i was doing it ‘correctly’ and it was ‘proper’.

In it simplest sense, to create an empty XML document in PowerShell do this: “$service = New-Object System.Xml.XmlDocument” and you have an XML document.  But how do you put things into it.

Okay, this is all about objects, and object manipulation.  You don’t just add tags in.  You create objects that are of the type $service and you add them back to $service in the correct order.

I began with this:

$service = New-Object System.Xml.XmlDocument
$tier = $service.CreateElement("Tier")
$tier.SetAttribute("Name","My Test Tier")

$vm = $service.CreateElement("VM")
$vm.SetAttribute("Name","My VM Name")

$tier.AppendChild($vm)
$service.AppendChild($tier)

I create the XML Document $service.  Then I create an Element of type $service and define a Name and value as an Attribute of that Element.  I repeat this and create a $vm element as well. 

If you query $service, you find that these things aren’t there.  They are three separate objects at this point.  They are all share the same object type of $service.  But nothing more.  Now I assemble them together.

I take the $tier object and I add the $vm object to it as a child.  This nests <vm> under <tier> in the XML.  I then repeat this adding this updated $tier object to $service as a child.

The above is fine enough.  However, I was informed that I was missing a root element.  To define the Document.

$service = New-Object System.Xml.XmlDocument
$root = $service.CreateElement("RootElement")

$tier = $service.CreateElement("Tier")
$tier.SetAttribute("Name","My Test Tier")

$vm = $service.CreateElement("VM")
$vm.SetAttribute("Name","My VM Name")

$tier.AppendChild($vm)
$root.AppendChild($tier)
$service.AppendChild($root)

I have been informed that simply doing what I just showed above is still not quite good enough.  It meets the requirement of a root element but totally missed on the intent or spirit.  We will get back to that.

So, what does this XML document look like?  Well, you can step through $service and try to imagine it in your head our you can send it out to a file and open it in notepad.

$service.Save(".\service.xml")

Open that up and you have:

<RootElement>
  <Tier Name="My Test Tier">
    <VM Name="My VM Name" />
  </Tier>
</RootElement>

Now.  I have some XML.  And I am feeling pretty proud of myself.

Why did I ever do this in the first place?  So I could do this:

PS C:\Users\Public\Documents> $service.GetElementsByTagName("Tier")

Name                                                     VM
----                                                     --
My Test Tier                                             VM

PS C:\Users\Public\Documents> $service.GetElementsByTagName("VM")

Name
----
My VM Name

Now I have associations that I can look for and query against.

Now, the fun part, meshing those two different activities together as one.  And I have the following:

$tiers = $s.Split(']')

$service = New-Object System.Xml.XmlDocument
$root = $service.CreateElement("RootElement")

foreach($tierString in $tiers) {

    if($tierString){  #ignore any empties
        $tier = $service.CreateElement("Tier")

        $e = $tierString.Split('[')

            $tier.SetAttribute("Name",$e[0])

            $VMs = $e[1].Split(",")

            foreach ($vmString in $VMs){
                if($vmString){
                     $vm = $service.CreateElement("VM")
                     $vm.SetAttribute("Name",$vmString)
                 }
                $tier.AppendChild($vm)
            }

    }
    $root.AppendChild($tier)
}
$service.AppendChild($root)

Now, back to that really lazy root element I created.  In practice, that should be some meta information about the XML document itself.  If you look at lots of XML you will see things like creation dates, versions, authors, and a name that is somehow descriptive.

After I create the $root object (with a better name) I just update it with a few attributes and I am good to go.

$root.SetAttribute("version","1.0")
$root.SetAttribute("createon",(Get-Date))
$root.SetAttribute("createdby","brianeh")

Now, a really short example of what I can now do with this information.

# query on a specific VM element with a Name equal to "Machine02"
# The Item(0) returns the XML object itself instead of a reference to it.  $me = $me.ItemOf(0)

$me = ($service.SelectNodes("//VM[@Name='Machine02']")).Item(0)

# What Tier do I belong to?
$me.ParentNode.Name

# Do I have Siblings or am I an only Child?
$me.NextSibling
$me.PreviousSibling
$me.ParentNode.ChildNodes.Count

Note:  be careful.  These queries are in XPath format, and they are case sensitive.

You can also simply walk the XML as PowerShell supports that as a ‘.’ notation path.

Friday, June 7, 2013

Handling freakishly long strings from CMD to PowerShell

This is one of those “quick, blog it before you forget it all” type of posts.  As well as “hey, I think I get it” and “the things you learn”.

I can thank a particular Microsoft PM for even causing me to look into this.  Never would I have expected that I would need to be prepared to handle an “extremely long” string.  What do I mean by extremely long?  Over 8200 characters, that is what I mean.

To quote the individual that caused me to spend time figuring this out: “I don't recommend this .. because <string in question> can expand to a very large string that will overflow the max # of chars you can pass from cmd.”

That is my entire point here.  I am not just in the PowerShell state of euphoria.  I have some process that is invoking PowerShell as a command calling my script and feeding it parameters.  Open a command prompt and type “PowerShell.exe /?” for a flavor of this world.

Well, what is that maximum number?  How big could this be?

Open a command window and start typing.  When you think you are done, keep going.  You will hit a limit, it is just below 8200 characters.  If you try to pass a string to a script and output it, you will be there.  I did this:

.\SampleScript.ps1 my incredibly long string where I kept typing and copy and pasting until I ran out of characters.

Within the script I captured the input in a special way and output the length and the string back to a file.  Note that param property “ValueFromRemainingArguments” (below) if this is not there, each space in that string gets treated like a new argument and within the script you end up with $args as an array.

Param (
   [parameter(Mandatory = $false, ValueFromRemainingArguments = $true)]
   $ComputerNames = ""
)
$ComputerNames.getType() | Out-File C:\users\Public\Documents\ComputerNames.txt
$ComputerNames.length | Out-File C:\users\Public\Documents\ComputerNames.txt -Append
$ComputerNames | Out-File C:\users\Public\Documents\ComputerNames.txt -Append

Also buried in this correspondence with this individual was a suggestion to write an executable and capture the string using stdIn, parse it, and then invoke PowerShell from there. 

Well, I am becoming a bit of a PowerShell junkie, and I am a lot more comfortable there than with C#.  And, I have to think about the poor sole that has to take care of this project when I finish.  Why give them some hack of an exe to take care of?

Lets back up.  StdIn.  What in the world is that?  I have never run across that with PowerShell. I am definitely not a developer either.

The best way that I can describe StdIn is a read stream.  Instead of passing in a string a stream is passed in and parsed when the end of stream is received.  After talking to a developer cohort, I learned that I actually use StdIn in PowerShell quite frequently.  Pipelining “in” uses StdIn.

So doing this:

$someString | .\ComputerNames.ps1

Uses the StdIn method for inputting the data.

But wait.  Okay, a bit of noise about StdIn and cmd limits.  what about the long strings?

Okay, pipeline. 

My test was a 24,000+ character string.

$someString = "However you want to make this really, incredibly long.  Keep going."
$someString.Length
$someString | .\SampleScript.ps1

But you need to change that param line so that it takes the pipeline.

Param
(
[parameter(Mandatory = $false, ValueFromPipeline = $true)]
$ComputerNames = ""
)

If you want to see what happens the other way, go back and try.  If you keep it all in PowerShell it works.  But if you call the PowerShell script from cmd it truncates due to the original issue I was warned about.

So, in the end, I did not have to write some exe that only parses this input, I actually used PowerShell instead.

Here is how I invoke:

%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command "'%ComputerNames' | .\SampleScript.ps1 -otherArg 'gibberish'"

Here is my script:

Param
(
[parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromRemainingArguments = $true)]
$ComputerNames = "",
[parameter(Mandatory = $true)]
[string]$otherArg = ""
)

$otherArg | Out-File C:\users\Public\Documents\ComputerNames.txt

$ComputerNames.getType() | Out-File C:\users\Public\Documents\ComputerNames.txt -Append
$ComputerNames.length | Out-File C:\users\Public\Documents\ComputerNames.txt -Append
$ComputerNames | Out-File C:\users\Public\Documents\ComputerNames.txt -Append

Thanks for reading. If you ask why? My only answer is because I have to, I have no other option. We don't always have interactive sessions at our disposal. Sometimes we are headless scripts running under some workflow engine.

==

My developer friend just uncovered the following this dies not support additional parameters to the string and may be able to handle strings that are longer yet:

File  Blah.ps1
$c = [Console]::In.ReadToEnd()
"Here"
$c

In use you still take your long input and pipe to the script, but the use of ‘reading in’ the input is more literal (for lack of a better description).

Wednesday, June 5, 2013

Discovering and initializing a data volume at VM provision

A few posts back I wrote about using PowerShell to find the DVD drive that a particular installer was attached to and then running that command line installer.

To take that a bit further I have a VM that I am deploying, and that VM has an empty VHDX attached to it.

This VHDX is on the second IDE controller (it needs to be available early in the boot process of the OS).  When I provision this VM the first time, I want to find, online, initialize, and format that virtual disk.

$disk = Get-Disk | where {($_.BusType -eq "ATA") -and ($_.IsBoot -eq $false)}

(You could also find the disk if it was on the SCSI controller)

$disk = Get-Disk | where {$_.BusType -eq "SCSI"}

And now for mounting, and formatting the disk.

Set-Disk -InputObject $disk -IsOffline $false

Set-Disk -InputObject $disk -IsReadOnly $false

Initialize-Disk -InputObject $disk -ErrorAction SilentlyContinue -WarningAction SilentlyContinue

$partition = New-Partition -InputObject $disk -UseMaximumSize –AssignDriveLetter

$partition | Format-Volume -FileSystem NTFS -NewFileSystemLabel "Cache" -Force:$true -Confirm:$false

And now you simply continue along with your scripting.

The reason that I capture the new partition to $partition is that there are lots of useful stuff in there for configuring things moving on.  Little things like: $partition.DriveLetter are highly useful.

Tuesday, May 21, 2013

Enabling Network Virtualization using SCVMM Run Script Command

So, if you are in the Fabric node of SCVMM 2012 SP1 you might happen to right click on a Hyper-V Server and notice the option “Run Script Command”.

This is great, it lest me push commands out to my Hyper-V Servers and run them, just like I do with Application Scripts in Service Templates.

I recently ran into a situation where I needed to enable the Network Virtualization binding on all of my Hyper-V Servers (seven of them).  And I had no desire to open a PSSession to each and run my script block that enables it.

Since I discovered this Script Command option in SCVMM, why not use it, I am here.

Like any good SCVMM admin I defined the command and then looked at the PowerShell script behind it.

(The big problem here is that I don’t see a way to save these Script Commands and run them again.  Big fail there.)

I then took that script and made it a bit more useful to me by getting all of my Hyper-V hosts and running my command on all of them at the same time.

And I figured that ‘why not’ this is the one step that all the SCVMM Network Virtualization setup is missing.  Frankly, I would expect SCVMM just to do this for me, but alas SP1 does not.

Here is my execution:

import-module virtualmachinemanager

$scriptSetting = New-SCScriptCommandSetting

Set-SCScriptCommandSetting -ScriptCommandSetting $scriptSetting -WorkingDirectory "" -PersistStandardOutputPath "" -PersistStandardErrorPath "" -MatchStandardOutput "" -MatchStandardError ".+" -MatchExitCode "[1-9][0-9]*" -FailOnMatch -RestartOnRetry $false -AlwaysReboot $false -MatchRebootExitCode "" -RestartScriptOnExitCodeReboot $false

$RunAsAccount = Get-SCRunAsAccount -Name "DomainAdmin"

$VMHosts = Get-SCVMHost | where { $_.VirtualizationPlatform -eq "HyperV" }

$scriptBlock = {

   $vSwitch = Get-VMSwitch -SwitchType External

   ForEach-Object -InputObject $vSwitch {

      if ((Get-NetAdapterBinding -ComponentID "ms_netwnv" -InterfaceDescription $_.NetAdapterInterfaceDescription).Enabled -eq $false){

         Enable-NetAdapterBinding -InterfaceDescription $_.NetAdapterInterfaceDescription -ComponentID "ms_netwnv"

      }

   }

}

ForEach ($VMHost in $VMHosts) {

   Invoke-SCScriptCommand -Executable "%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe" -TimeoutSeconds 120 -CommandParameters "-ExecutionPolicy RemoteSigned -command $scriptBlock" -VMHost $VMHost -ScriptCommandSetting $scriptSetting -RunAsAccount $RunAsAccount

}

Be sure to have the SCVMM Console installed, and modify your RunAs account name.

That Set-SCScriptCommandSetting line is all about the error handling for the script.  The only non-default setting I have in here is making sure that my hypervisors were not rebooted, no matter what happened.

Wednesday, May 1, 2013

Discovering programs on a disk to run silent installers

I recently worked through my version of a PowerShell snip that has to discover in installer and run it.

In my case that installer is on an ISO that is attached to a VM.  And my script runs within the VM.

Now, this should be easy, just find the DVD drive, and run the installer.

Well, as always happens, it is not that easy in my case.  Come to find out, I could have multiple ISO attached at the moment my script is running, and I need to detect the correct one.  I also have to make sure that the installer exists before I try to run it and cause an error.  (there is always a need for error handling).

If I didn’t have this mess I could just assume that my ISO is D:\ and put in the path and move on.

First, ask yourself if the ISO will ALWAYS be on D:\?  If not, then you need to find the DVD drives and specifically those that have something mounted.  From within the running OS, not at some VM management layer.

I do that with the following:

# CD-ROM selects anything in the DVD drive.  The size ensures that something is mounted.
$dvdDrives = Get-Volume | where {$_.DriveType -eq "CD-ROM" -and $_.Size -gt 0}

I also have different installers for x86 and x64, so I have to detect the ‘bit-ness’ of the OS and smartly choose the correct installer.  A bit of searching turned me to this reliable way:

Switch ([System.IntPtr]::Size)
{
    4 {
        # x86
       }
    }
    8 {
       # x64
       }    
    }
}

Now, I have to build the path so that later on in my script I can run it.

If (Test-Path -Path ($dvd.DriveLetter + ":\Installer\") -PathType Container){
    $InstallMedia = Get-ChildItem -Path ($dvd.DriveLetter + ":\Installer\") -recurse -Filter "ServerInstaller.exe"
}

And, before attempting to run it, I need to test that the file really exists. And what is the literal path to the installer. Because how I got here was by testing for the folder structure, not by searching for the individual files (which would take a lot longer).

If ($InstallMedia -ne $null){
    If (Test-Path $InstallMedia .FullName){
        $InstallPath = $InstallMedia .FullName
    }
}

The entire script:

# CD-ROM selects anything in the DVD drive.  The size ensures that something is mounted.
$dvdDrives = Get-Volume | where {$_.DriveType -eq "CD-ROM" -and $_.Size -gt 0}

# Since a VM could have more than one DVD drive, we need to find the correct one.
foreach ($dvd in $dvdDrives){
    Switch ([System.IntPtr]::Size)
    {
        4 {
            If (Test-Path -Path ($dvd.DriveLetter + ":\x86\") -PathType Container){
                $Media = Get-ChildItem -Path ($dvd.DriveLetter + ":\x86\") -recurse -Filter "ServerSetup.exe"
            }
        }
        {
            If (Test-Path -Path ($dvd.DriveLetter + ":\x64\") -PathType Container){
                $Media = Get-ChildItem -Path ($dvd.DriveLetter + ":\x64\") -recurse -Filter "ServerSetup.exe"
            }    
        }
    }

    If ($Media -ne $null){
        If (Test-Path $Media.FullName){
            $FilePath = $Media.FullName
        }
    }
}

Start-Process -FilePath $FilePath –ArgumentList “/quiet “ -Wait -NoNewWindow
"Done waiting for the installer"

Wednesday, February 13, 2013

SCVMM Service Template for the first DC in a Forest – the bits

So here goes nothing.  Why not hand it over just to see how this Service Template Export and Import process really works.

In theory, you simply download my Service Template and then Import it.  It will give you the custom application resource folder and the scripts.

You need to bring the Server 2012 evaluation VHD image and place it in your Library.

Be sure to hook your logical network settings, connect to the VHD image.

When you configure your deployment you should have to fill in the domain FQDN, NetBIOS name, and recovery password.  Then click go. 

That is the theory.

Why not give it a go?

I ask one thing though, if you download and try – can you please leave comments and feedback about the experience.

Thanks!

 

BATCH Script Domain Controller Service Template

PowerShell Script Domain Controller Service Template