Showing posts with label Service. Show all posts
Showing posts with label Service. Show all posts

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.

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.

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

Tuesday, February 12, 2013

SCVMM Service Template for the first DC in a Forest – part 2

Okay, so I posted the traditional way of handling this, with a BATCH file.

But, in reality all I did was sue a BATCH file to in turn process a PowerShell script.  I considered this silly.  There must be a way to process the PowerShell script without having to use the BATCH script.

I mean, come on.  This is Server 2012 I am using and PowerShell v3.  Yes, I know there are some advanced things that ca be done with BATCH scripting (I have done some in my history), but think out of the box here.

So, I spent bunches of time playing around with this (so you wouldn’t have to (if you stumbled on my post)).

In the end, it wasn’t that difficult, just had to think about things a bit differently.

Oh, and one important thing I left out of my previous post.  Use a local administrator Run As account for adding the local administrator admin credentials to the OS and the same Run As account a second time to process the scripts.

So, here is the script the PowerShell way:

param (
[string]$domainName,
[string]$netbiosName,
[string]$safeModePass
)

# Build a domain controller and the test domain.

# Add the RSAT tools
Add-WindowsFeature RSAT-AD-Tools

# Add the features
Add-WindowsFeature AD-Domain-Services -IncludeAllSubFeature -IncludeManagementTools
Add-WindowsFeature DNS -IncludeAllSubFeature -IncludeManagementTools
Add-WindowsFeature GPMC -IncludeAllSubFeature -IncludeManagementTools

# convert the password to a secure string as required
$secPass = ConvertTo-SecureString -String $safeModePass -AsPlainText -Force

# Create the Forest and Domain
Install-ADDSForest -CreateDnsDelegation:$false -DomainMode Win2012 -DomainName $domainName -DomainNetbiosName $netbiosName -ForestMode Win2012 -InstallDns -Force -SafeModeAdministratorPassword $secPass

I know what you are thinking, that can be shortened.  And my reply; yes, it can.  And you advanced folks, go right ahead.

Now, in the Application Configuration of the Tier in the Service.  Two pre-install scripts.

The first pre-install script is to set script execution to RemoteSigned:

The executable program is: %WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe

And the Parameters are: -command set-executionpolicy remotesigned –force 

(I don’t have a Run As account defined BTW).

image

The second pre-install script is everything above.  But those are included in the Custom Resource Package as a .ps1 file.

The executable program is the same.  The Parameters are different: -file .\DomainController.ps1 @DomainName@ @DomainNetbiosName@ @SafeModeAdministratorPassword@

And the Run As account is my local admin run as account profile.  And the timeout needs to be turned up to about 600 seconds.

image

That is it.  I tried it a few times.  It works. 

Monday, February 11, 2013

SCVMM Service Template for the first DC in a Forest – part 1

I am teaching myself about Service Templates in SCVMM and I always like to take something that I am doing and repurpose it.

Today, I finally had success with taking the PowerShell scripts behind creating a new domain controller in a new forest and automating that using the SCVMM Service Template model.

Oh my (quoting George Takei).  What an interesting adventure this has been.

So, if you are looking for a real world examples of building your own Template, here is it.  No references to Pet Shop here. 

Also, this is not a walkthrough or a point and click post.  I am expecting you to have some familiarity with setting up SCVMM and read all the other blogs about building an SCVMM Service Template.  I am going straight to the peculiar things that you need to be aware of or do to make this happen.

 

First:

I begin with the Server 2012 evaluation VHD (nice and small, prepared with sysprep, no baggage.) and I place that in my SCVMM Library.

Second:

And this is (what I think is) the key – I build some scripts.  The SCVMM Library comes with a few “Application Frameworks” and these are Custom Resources.  Server App-V and WebDeploy are delivered this way.

How do you do this?  Go to your SCVMM Library share, and model the built in ones.

Create a Folder called MyFoo.cr.  Add a file to that called “SCVMMCRTag.cr”  - Don’t copy an existing one, create one.

Add your scripts to this folder.

The Scripts:

Welcome back to the world of BATCH.  If you have been here before, you will recall it fondly.  If you have never been here, you must be relatively young.  There are some excellent web sites with some excellent BATCH command references.  Just search a bit (there aren’t lots, so you find them rather quickly).

Why batch – look at the MSFT included stuff.  Fun with BATCH.  And it ‘just works’.

So here is my trick:  Running PowerShell commands from a BATCH script:

echo Set the Execution Policy to RemotedSigned
%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command set-executionpolicy remotesigned –force

And for this exercise I can install all the required features of Active Directory and DNS:

REM echo Add the RSAT tools
%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command Add-WindowsFeature RSAT-AD-Tools

REM echo Add the Windows Features
%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command Add-WindowsFeature AD-Domain-Services -IncludeAllSubFeature –IncludeManagementTools

%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command Add-WindowsFeature DNS -IncludeAllSubFeature –IncludeManagementTools

%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -command Add-WindowsFeature GPMC -IncludeAllSubFeature -IncludeManagementTools

And this is where BATCH fails.  This needs to be totally unattended.  And the cmdlet to create the AD Forest requires a secure string.  I can’t do that in BATCH.  I need to actually use a script (or call the command and add my script as a script block).

This PowerShell script will be in the same folder as the BATCH script (MyFoo.cr).

param (
[string]$domainName,
[string]$netbiosName,
[string]$safeModePass
)

# convert the password to a secure string as required
$secPass = ConvertTo-SecureString -String $safeModePass -AsPlainText -Force

# Create the Forest and Domain
Install-ADDSForest -CreateDnsDelegation:$false -DomainMode Win2012 -DomainName $domainName -DomainNetbiosName $netbiosName -ForestMode Win2012 -InstallDns -Force -SafeModeAdministratorPassword $secPass

Okay, back to the batch script.  You need to properly call the PowerShell script from the BATCH script.

REM Running the PowerShell Domain Controller script
%WINDIR%\System32\WindowsPowerShell\v1.0\PowerShell.exe -file %~dp0\DomainController.ps1 %domName% %domNBios% %recoPass%

But what are those “%” thingies?  Parameters.  I pass parameters to the BATCH script, which are in turn passed to the PowerShell script.  All because of the Secure String.

Now, setting this in the Service Template:

The executable program is cmd.exe (because we are using the command prompt)

And the parameters are: /q /c DCInstall.cmd @DomainName@ @DomainNetbiosName@ @SafeModeAdministratorPassword@

The /q is for ‘quiet’ and the /c defines the ‘command’ – the /c needs to be the last entry of the line.  The @thing@ are the parameters that SCVMM will prompt you for when you deploy.

And the Run As account is my local admin run as account profile.  And the timeout needs to be turned up to about 600 seconds.

And the Script resource package is that folder you created that you put the scripts into.  This gets copied to your VM via BITS (the VM OS does a pull from the Library share BTW), executed, and then deleted on success.

It should look something like this:

image

And the Custom Resource:

image

 

Next post, a twist.  Who wants to call the command prompt and relive the glory days of BATCH all the time?  Why not use only PowerShell??