The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

Archive for the ‘MDT’ Category

OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 1–Getting the Hardware info)

Posted by Mikael Nystrom on January 6, 2014

This is post refers to this post http://deploymentbunny.com/2013/12/29/os-deployment-oob-install-of-windows-server-2012-r2-using-mdtwds-and-powershell/

Out of Band or Bare Metal installation requires information regarding the hardware, that is no surprise. We need to to be able to define settings that can be retried from the hardware. In many/most client deployment scenarios I see people using the MAC Address or, Serial Number but I use the GUID number. When it comes to server they don’t really have one NIC and when it comes to Hyper-V that MAC address will be more or less removed since the machine in most cases is turning the NICs into switches and then virtual NICs will be on top of that, so GUID number is better. All “normal” brands have that, at least with new server hardware. In this case I’m deploying HP Servers and they have iLO which is basically an other name for IPMI. In the case of iLO it is rather easy to access that information, you don’t even need to be authenticated, all the information we need is there (http://deploymentbunny.com/2013/12/18/nice-to-know-getting-hardware-infoilo-data-using-native-powershell-and-no-need-for-credentials/)

By reading the XML data in turn it into an object it is rather easy to use the data in PowerShell.

Below you can see the part we use to grab that data.

image

/mike

Posted in Deployment, iLO, MDT, PowerShell, Windows Server 2012 R2 | Tagged: , , | 5 Comments »

PowerShell is King – Building a Reference Image Factory

Posted by Mikael Nystrom on January 6, 2014

In the world of deployment a reference image is where all begins, basically we take the ISO/WIM from the vendor, install it, tweak it, patch it and on the other side we now a have a customized reference image that is more suitable for our needs. This applies to both clients and servers. There are two ways of doing this, the correct way and the incorrect way. The correct way is repeatable and as automated as possible. This blog is about the correct way and how to automate it just a bit more then usual. You can of coarse modify the script so it will do more, for example upload the images to the correct destination.

Acknowledgement goes to:

What do I need to get this working?

Step 1: Set up Microsoft Deployment Toolkit 2013 on a server

Step 2: Import Operating Systems, applications and create your task sequences

Step 3: Install Windows Server 2012 R2 (or Windows 8.1) with Hyper-V as your “creator”

Step 4: Download the script and enjoy the show

Note:

  • The script is designed to run on the Hyper-V machine, but it is possible to run this remote either using Remote-Sessions or defining –Computer on every Commands that relates to Hyper-V
  • The Solution is tested on Windows Server 2012 R2 with MDT 2013 and ADK 8.1 BUT should work just fine on Windows 8.1

How does the script work?

image

The PowerShell module has a couple of functions

New-AutoGenRefImages

This function will connect to your MDT server, grab the boot ISO, read all TaskSequences from Task Sequences\REF

image

And for each of them build a VM with the same name as the task sequence. When they are all built it will power them on one by one, booting from the ISO and then run the task sequence that corresponds to the name of the the VM. So if you have a TS with the ID of RW81.x86, it will build a VM with that name and run the TS with that ID on that VM.

You might ask your self how that is done?. I’m not using the database, not using GUID number or Mac’s. The main reason is that I want a solution with as little dependencies as possible, so it will work anytime at any customer (almost). Instead I’ loading the drivers for KVP (Key Value Pair Exchange) in WinPE, I grab the name of the VM before the customsettings.ini is read using a userexit script in bootstrap.ini so I have a Property called VMNameAlias wich then is used to control the deployment process, a neat solution IMHO (more on that later)

Remove-AutoGenRefImages

This function will destroy and remove all VMs, it does this by getting all task sequence ID’s from the MDT server, and find corresponding VM’s and then destroy and clean up.

New-RefImage

This is a manual process, you now need to KNOW the Task Sequence ID, since that is a validation in the CMDLET

Remove-RefImage

Also a manual process, it will destroy/delete/cleanup whatever VMname you type in, note that there will be NO questions, it just deletes them, so don’t type in DC01 or something like that.

Get-RefTaskSequence

A simple CMDLET that lists all task sequences that are in the \REF folder in MDT

The Details

Download the Scripts from here: http://sdrv.ms/1hqoJIh

Download devcon.exe from here: http://support.microsoft.com/kb/311272/en-us

Modify ImageFactoryV2.xml

This is my sample XML file and you need to modify it so it will work in your environment.

<Settings>
<DeploymentShare>\\SRVHOST555\MDTBuildLab$</DeploymentShare>
<HyperVHost>SRVHOST555</HyperVHost>
<HyperVHostNetwork>UplinkSwitch</HyperVHostNetwork>
<HyperVStorage>E:\VMs</HyperVStorage>
<HyperVISOFolder>E:\ISO</HyperVISOFolder>
<HardwareProfile>MDT 2010 Profile</HardwareProfile>
<TaskSequenceFolder>MDT:\Task Sequences\REF</TaskSequenceFolder>
<StartUpRAM>2</StartUpRAM>
<VLANID>0</VLANID>
<VHDSize>60</VHDSize>
</Settings>

Modify bootstrap.ini

Bootstrap.ini needs some modification (besides being silent). You need to add the following:

image

In text:

[Settings]
Priority=Default

[Default]
DeployRoot=\\SRVHOST555\MDTBuildLab$
UserDomain=NETWORK
UserID=Administrator
UserPassword=Password02
SkipBDDWelcome=YES
SubSection=ISVM-%IsVM%

[ISVM-True]
UserExit=LoadKVPInWinPE.vbs

This will load a userexit script that installs the driver for KVP and create a fake services that will allow it to load.

Modify customsettings.ini

You need to modify customsettings.ini so it will read in the values from the KVP correctly

image

In text:

[Settings]
Priority=Init,Default
Properties=VMNameAlias

[Init]
UserExit=ReadKVPData.vbs
VMNameAlias=#SetVMNameAlias()#

[Default]
TaskSequenceID=%VMNameAlias%

You need to add the Property VMNameAlias under the Settings Section

You need to create a new Section called Init that runs the UserExit

You need to set the TaskSequenceID to match the returned value from the UserExit script

Modify the boot image:

You need to make sure that those two scripts are added correctly and we also need the driver for KVP. One easy way is to use the “Extra” folder feature in MDT, whatever you put in that folder will end up on the boot image.

My deployment share is located in

E:\MDTBuildLab

so I created a folder called

E:\MDTBuildLab\Extra

In that Folder I two folders, Deploy and KVP. In the folder Deploy I have a subfolder called Scripts.

Like this:

image

Content of the KVP folder:

In the KVP folder you need to add the driver for KVP, and that you can do by searching for VMGuest.iso on your Hyper-V host, it is in C:\Windows\System32, mount that is and extract the drivers.

The driver you need is in the support\x86\Windows6.x-HyperVIntegrationServices-x86.cab and the folder is namned x86_wvmic.inf_31bf3856ad364e35_6.3.9600.16385_none_968283a5680527fe

(read Keith Garners blog for details, Note: In Keith’s blog it is 64 bit, I’m using the 32 bit driver, since I boot from the x86 boot image. Therefore the name is different of course.)

You also need to store devcon.exe in that folder

When you got them, it should look like this in the folder

image

Content of the Deploy\Scripts folder

In this folder you store the LoadKVPinWinPE.vbs script

Like this:

image

Update the BootImage:

In the Boot Image setting for WinPE, for the setting called Extra directory to add, browse to your folder, apply, update boot image.

image

The Scripts:

LoadKVPInWinPE.vbs

Mainly “borrowed” from Keith’s blog, just modified to use devcon.exe instead the method suggested by Keith


option explicit

function UserExit(sType,Swhen,Sdetail,bSkip)
oLogging.CreateEntry “USEREXIT:ModelAliasExit.vbs started: ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo

    If ucase(oEnvironment.Item(“ISVM”)) = “TRUE” and oEnvironment.Item(“OSVERSION”) = “WinPE” then

        oLogging.CreateEntry “Load the Integration Components”, LogTypeInfo
oUtility.RunWithConsoleLogging “\KVP\devcon.exe /r install \KVP\wvmic.inf vmbus\{242ff919-07db-4180-9c2e-b86cb68c8c55}”
CreateFakeService “TermService”, “Remote Desktop Service”, “FakeService.exe”
GetObject(“winmgmts:root\cimv2″).Get(“Win32_Service.Name=’vmickvpexchange’”).StartService()
oUtility.SafeSleep 10000
LoadVariablesFromHyperV

    End if

    ‘ Write back an unique number to the host to let them know that the variables have been loaded.
oUtility.RegWrite “HKLM\SOFTWARE\Microsoft\Virtual Machine\Auto\HydrationGuestStatus”,”eb471002-58aa-473a-850f-7b626613055f”

    Userexit=success

end function

‘ ———————————————————

Function CreateFakeService (sName,sDisplayName,sPathName )

    Dim objService
Dim objInParam

    ‘ Obtain the definition of the Win32_Service class.
Set objService = GetObject(“winmgmts:root\cimv2″).Get(“Win32_Service”)

    ‘ Obtain an InParameters object specific to the Win32_Service.Create method.
Set objInParam = objService.Methods_(“Create”).inParameters.SpawnInstance_()

    ‘ Add the input parameters.
objInParam.Properties_.item(“Name”) = sName
objInParam.Properties_.item(“DisplayName”) = sDisplayName
objInParam.Properties_.item(“PathName”) = sPathName
objInParam.Properties_.item(“ServiceType”) = 16
objInParam.Properties_.item(“ErrorControl”) = 0
objInParam.Properties_.item(“StartMode”) = “Manual”
objInParam.Properties_.item(“DesktopInteract”) = False

    ‘ Execute the method and obtain the return status.
CreateFakeService = objService.ExecMethod_(“Create”, objInParam).ReturnValue

End function

Function LoadVariablesFromHyperV

    Dim objReg
Dim aSubValues
Dim aValues
Dim SubVal

    oLogging.CreateEntry “Has MDT Environment Variables in Integration Components.”, LogTypeInfo
Set objReg=GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”)
objReg.EnumValues &H80000002, “SOFTWARE\Microsoft\Virtual Machine\External”, aSubValues, aValues

    If isArray(aSubValues) then
For Each SubVal in aSubValues
oLogging.CreateEntry “Found Key: [" & SubVal & "]“, LogTypeInfo
oEnvironment.Item(SubVal) = oUtility.RegRead(“HKLM\SOFTWARE\Microsoft\Virtual Machine\External\” & SubVal)
Next
End if

End Function


ReadKVPData.vbs


‘//—————————————————————————-
‘// Version: 1.0 – Jan 04, 2013 – Mikael Nystrom
‘// Twitter @mikael_nystrom
‘// Blog
http://deploymentbunny.com
‘// This script is provided “AS IS” with no warranties, confers no rights and
‘// is not supported by the author
‘//—————————————————————————-
‘ //
‘ // Usage:     Modify CustomSettings.ini similar to this:
‘ //              [Settings]
‘ //              Priority=SetAlias, Default
‘ //              Properties=VMNameAlias
‘ //
‘ //              [SetAlias]
‘ //              VMNameAlias=#SetVMNameAlias()#
‘ // ***** End Header *****

Function UserExit(sType, sWhen, sDetail, bSkip)

    oLogging.CreateEntry “UserExit: started: ” & sType & ” ” & sWhen & ” ” & sDetail, LogTypeInfo
UserExit = Success

End Function

Function SetVMNameAlias()
oLogging.CreateEntry “UserExit: Running function SetVMNameAlias “, LogTypeInfo
SetVMNameAlias = “”
SetVMNameAlias = oShell.RegRead(“HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters\VirtualMachineName”)
oLogging.CreateEntry “UserExit: SetVMNameAlias has been set to ” & SetVMNameAlias, LogTypeInfo
oLogging.CreateEntry “UserExit: Departing…”, LogTypeInfo
End Function


ImageFactoryV2.psm1


<#
.Synopsis
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
.INPUTS
Inputs to this cmdlet (if any)
.OUTPUTS
Output from this cmdlet (if any)
.NOTES
General notes
.COMPONENT
The component this cmdlet belongs to
.ROLE
The role this cmdlet belongs to
.FUNCTIONALITY
The functionality that best describes this cmdlet
#>
<#
.Synopsis
Short description
.DESCRIPTION
Long description
.EXAMPLE
Example of how to use this cmdlet
.EXAMPLE
Another example of how to use this cmdlet
#>
# Read Settings from XML
[xml]$Global:Settings = Get-Content .\ImageFactoryV2.xml
$Global:DeploymentShare = $Global:Settings.Settings.DeploymentShare
$Global:StartUpRAM = 1024*1024*1024*$Global:Settings.Settings.StartUpRAM
$Global:VHDSize = 1024*1024*1024*$Global:Settings.Settings.VHDSize
$Global:SWitchName = $Global:Settings.Settings.HyperVHostNetwork
$Global:VMLocation = $Global:Settings.Settings.HyperVStorage
$Global:HyperVISOFolder = $Global:Settings.Settings.HyperVISOFolder
$Global:TaskSequenceFolder = $Global:Settings.Settings.TaskSequenceFolder
$Global:VLANID = $Global:Settings.Settings.VLANID

function New-AutoGenRefImages{
Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

    #Check if ISO exists
$ISOFileExist = Test-Path “$($Global:DeploymentShare)\Boot\$($ISO)”  -ErrorAction SilentlyContinue
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Create Folders
$Null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
Copy-Item “$($Global:DeploymentShare)\Boot\$($ISO)” $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
$ISOFileExist = Test-Path ($Global:HyperVISOFolder + “\” + $ISO) -ErrorAction Stop
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Check if VMSwitch on host exists
$VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
If($VMSwitchExist.Name -ne $Global:SWitchName){
Write-Host “Unable to find VMSwitch, exit”
BREAK
}

    #Create the VMs
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){

        #Set VMName to ID
$VMName = $TS.ID

        #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “VM already exist, exit”
BREAK
}

        $VM = New-VM –Name $VMname –MemoryStartupBytes $Global:StartUpRAM -SwitchName $Global:SWitchName -NewVHDPath “$Global:VMLocation\$VMName\Virtual Hard Disks\$VMName.vhdx” -NewVHDSizeBytes $Global:VHDSize -Path $Global:VMLocation
Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + “\” + $ISO)

        #Set
Get-VM -Name $VMName | Set-VMProcessor -CompatibilityForMigrationEnabled $True
Get-VM -Name $VMName | Set-VMProcessor -Count 2
If($Global:VLANID -notlike “0″){
Get-VM -Name $VMName | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
}
}
Foreach($TS in $RefTS){
#Set VMName to ID
$VMName = $TS.ID
$VM = Get-VM -Name $VMName
$VM | Start-VM
Start-Sleep “10″
while($VM.State -like “Running”){
Write-Output “Waiting for $VMName to finish.”
Start-Sleep “120″}
Write-Output “$VMName is done, checking for more”
}
}
}
function Remove-AutoGenRefImages{
Process
{

    #Connect to MDT:
$Null = Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction SilentlyContinue
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

        #Remove the VMs
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){

            #Set VMName to ID
$VMName = $TS.ID

            #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “Removing $VMName”
$VMToRemove = Get-VM -Name $VMName
$FolderPath = $VMToRemove.path
if($VMToRemove.state -like “Running”){Stop-VM $VMToRemove -Force}
$VMToRemove | Remove-VM -Force
$FolderPath | Remove-Item -Force -Recurse
}
}
}
}
function New-RefImage{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[String]
$TaskSequenceID
)

Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

    #Check if ISO exists
$ISOFileExist = Test-Path “$($Global:DeploymentShare)\Boot\$($ISO)”  -ErrorAction SilentlyContinue
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Create Folders
$null = New-Item -Path $HyperVISOFolder -ItemType Directory -Force -ErrorAction SilentlyContinue

    #Copy the BootImage from MDTServer to Hyper-VHost
Copy-Item “$($Global:DeploymentShare)\Boot\$($ISO)” $Global:HyperVISOFolder\ -Container -Force -ErrorAction Stop

    #Check if ISO exists
$ISOFileExist = Test-Path ($Global:HyperVISOFolder + “\” + $ISO) -ErrorAction Stop
If($ISOFileExist -like ‘False’){
Write-Host “Unable to find ISO, exit”
BREAK
}

    #Check if VMSwitch on host exists
$VMSwitchExist = Get-VMSwitch -Name $Global:SWitchName -ErrorAction SilentlyContinue
If($VMSwitchExist.Name -ne $Global:SWitchName){
Write-Host “Unable to find VMSwitch, exit”
BREAK
}

    #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “VM already exist, exit”
BREAK
}

    $VM = New-VM –Name $TaskSequenceID –MemoryStartupBytes $Global:StartUpRAM -SwitchName $Global:SWitchName -NewVHDPath “$Global:VMLocation\$TaskSequenceID\Virtual Hard Disks\$TaskSequenceID.vhdx” -NewVHDSizeBytes $Global:VHDSize -Path $Global:VMLocation
Add-VMDvdDrive -VM $VM -Path ($Global:HyperVISOFolder + “\” + $ISO)

    #Set
Get-VM -Name $TaskSequenceID | Set-VMProcessor -CompatibilityForMigrationEnabled $True -VM $VM

    #Set
Get-VM -Name $TaskSequenceID | Set-VMProcessor -Count 2

    #Set
If($VLANID -notlike “0″){
Get-VM -Name $TaskSequenceID | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -Access -VlanId $VLANID
}

    }

}
function Remove-RefImage{
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ValueFromRemainingArguments=$false,
Position=0)]
[String]
$VMName
)
Process
{

    #Check if VM exists
$VMexist = Get-VM -Name $VMName -ErrorAction SilentlyContinue
If($VMexist.Name -like $VMName){
Write-Host “Removing $VMName”
$VMToRemove = Get-VM -Name $VMName
$FolderPath = $VMToRemove.path
if($VMToRemove.state -like “Running”){Stop-VM $VMToRemove -Force}
$VMToRemove | Remove-VM -Force
$FolderPath | Remove-Item -Force -Recurse
}
}
}
function Get-RefTaskSequence{
Process
{

    #Connect to MDT:
Add-PSSnapIn Microsoft.BDD.PSSnapIn -ErrorAction Stop
Remove-PSDrive MDT -ErrorAction SilentlyContinue
$Null = New-PSDrive -Name MDT -PSProvider MDTProvider -Root $Global:DeploymentShare -Force
$MDTSettings = Get-ItemProperty MDT:
$ISO = $MDTSettings.’Boot.x86.LiteTouchISOName’

        #Get TS
$RefTS = Get-ChildItem $Global:TaskSequenceFolder -Recurse
Foreach($TS in $RefTS){
New-Object PSObject -Property @{
TaskSequenceID = $TS.ID
Name = $TS.Name
Comments = $TS.Comments
Version = $TS.Version
Enabled = $TS.enable
LastModified = $TS.LastModifiedTime
}
}
}
}

Export-ModuleMember -function *


/mike

Posted in Deployment, MDT, System Center 2012, System Center 2012 R2 | Tagged: , , | 4 Comments »

OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell

Posted by Mikael Nystrom on December 29, 2013

PowerShell is amazing, it is now possible to do all those things I know would be possible, but did require compiled code or time I don’t have (Still working as an consultant in the real world you know). In my line of work besides automation, flexibility is one other keyword and that is very often used in conjuction with Windows Server deployment. Now, Windows Server is also amazing, it is a multipurpose operating system and multipurpose also means that while client deployment is pretty standard these days, server deployment is not even close to that. In SCCM we have great OS Deployment (even better with MDT integration), but in many cases I’m not allowed to use it. MDT is very flexible and many orgs are using MDT for server deployment and SCCM for clients and they have their reasons, but MDT lacks some of the features that SCCM/MDT does have. We also have an upcoming star and that is SCVMM, while SCVMM has some of the benefits that SCCM have but MDT does not have, well you get the point. But, if you could have bits and pieces from each and every one, and does not require an investment in System Center knowledge, what about having only Active Directory. Windows Deployment Services, DHCP/DNS, MDT and a PowerShell script? Wouldn’t that be nice?

The parts

It is not that hard to setup and configure, but still, there is a lot of moving parts and you need to understand them all, therefore it is dived in the following parts for more details
(note I’ll add the links as soon as I have written them, ok)

  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 1–Getting the Hardware info)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 2–Pre-stage device in AD)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell  (Part 3–Pre-stage device in MDT)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 4–Controlling Power remote)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 5–Controlling Drivers)
  • OS Deployment – Out Of Band install of Windows Server 2012 R2 Using MDT,WDS and PowerShell (Part 6–Apps and Firmware)

The Script

If you know this stuff and just need the script, download it from here: http://sdrv.ms/JCo5bO

Run Import-Module .\ServerDeployment-v1.psm1 –Verbose to import the module

image

run Get-Module to verify

image

To see all the functions you now have, just run Get-Command – Module ServerDeployment-v1

image

to get all the command syntax, just type Get-Command -Module ServerDeployment-v1 –Syntax

image

There is builtin help with command samples, just use Get-Help Command to get the help

image

Note: The script will assume certain things:

There are just a few hardcoded paths, its for the  two modules (yes, there are others way to solve the problem)

Make sure the dependent POSH modules are located here:

  • Import-Module ‘C:\Program Files\Hewlett-Packard\PowerShell\Modules\HPiLOCmdlets’ -ErrorAction Stop
  • Import-Module ‘C:\Program Files\Microsoft Deployment Toolkit\MDTDB.psm1′ -ErrorAction Stop

One last thing, this is not for beginners, you really need to understand the bits and pieces this time.

/mike

Posted in Deployment, iLO, MDT, PowerShell, Windows Deployment Services, Windows Server 2012 R2 | Tagged: , , | 3 Comments »

PowerShell is King – Create a webpage containing LTI/ZTI Deployment issues with information and links to logs

Posted by Mikael Nystrom on December 29, 2013

Knowing is better than guessing, that is an indisputable fact as far as I know and since we try to automate more and more (someone wrote –automating the world, line by line and that is so darn correct) we now need to monitor much more. OS Deployment has been possible to automate for many years, but the level of monitoring to see if everything is working correctly is in place and there are many reasons for that, some solutions just takes forever to deploy and configure and some takes forever to understand how they work.

The Problem:

We need to be able to see if everything works as expect, we all work in the Service Sector, we are suppose to service our organizations and help our users so they can do whatever they are suppose to do (I know, working in IT is not that cool anymore). If you have MDT you could enable the monitoring feature, but it will only tell you ongoing deployments and if they went well or not, you cannot see the issues, only the number of issues. If you have SCCM it is far better, but, better could be better…

The Solution

In MDT there is a monitoring feature and what not so many know about is that it is actually writing to the event log.

$MDTevents = Get-EventLog -LogName Application -Source MDT_Monitor -EntryType Warning,Error
$MDTevents | Select Message

image
Output from running the commands above.

So, if we could create script that dumps that, split the message into 3 objects, machine name, type of error, and message, add the path to the logs for each machine we have a solution, right?

Issue Number one

The event log is fantastic, it has so many parameters to work with, but in this case it does not work, since all data is just a string in the event it self, so we need to extract that and “bend the rules a bit”, this is what we get if we don’t do anything at all

image
As you can see, it is all in the EventData, just as a dumb string.

With this little function we can now dump the data, turn the string into 3 objects, flip them around so that the computer name comes first (like to sort it on computer name), remove junk

image

Issue Number two

Converting to HTML with links to the logs, well that can be done rather easy using this part

image
Here you can see that we dump out the data running the Function Get-MDTIssues with a select statement that on the first position creates a new object called “link” and it will add a href tag on the computer name, so now we have a nice HTML page, well not really. there is another problem

Issue Number three

ConvertTo-HTML does not like HTML, it will of course convert everything to HTML, including HTML and the HTML we had is no HTML anymore…

But, Convertto-html is an object, so we can of course convert that on the fly using –replace and at the same time we can add the computer name correctly to the server we are running this on

image

Issue Number four

Now everything works, Yeah, well no, as soon as you have this “not-so-very-designed-web-page” you will be able to click the links and THAT works, you will end up in the log folders

image

So let us click one of them:

So far so good:

image

But you cannot click any of the links until you add a mime type for .log in IIS

image

Install and Configure

  • Download file from here: http://sdrv.ms/1h4WrD7
  • Store it locally on the MDT server (The server with the Deployment workbench, it is possible to run the script from an other machine, but then you need to modify the script to read the log from another computer)
  • Make sure that MDT Monitoring is enabled

image

  • Make sure that CustomSettings.ini is correctly configured to store the logs and to enable to send monitor data
    • SLShare=\\SRVMGT01\Logs$
    • EventService=http://SRVMGT01:9800
  • Add the IIS Feature
  • Add two Web Applications

image

  • Enable Directory Browsing for Logs and MDT (If you call the file default.htm or similar you don’t need that)
  • Schedule the script to run (You could a be smart, schedule a task based on the MDT_Monitor to run the script for warnings and errors

imageimage

  • Testing could be done in two ways, you could either deploy a machine and hope it fails or you could run this POSH command:

Write-EventLog -LogName Application -Source MDT_Monitor -EntryType Warning -EventId 2000 -Message "Error logged for computer TEST01: Application Install – HP Support Pack returned an unexpected return code: 1"

image

and if everything works correct, well you should be able to see that in the webpage

image

Happy “Warnings, errors and failures”

/mike

Posted in Deployment, MDT, SCCM | Tagged: , , | 6 Comments »

Nice to Know–Getting Make and Model using CMD or PowerShell

Posted by Mikael Nystrom on December 19, 2013

Trust me, this is not a new thing, rather I get the question every time on a session (before or after) or when working on a customer site, how can I extract the Make and Model from the machine? So, as long as people are asking me, I think I should answer, right? :-)

Make and Model is commonly used in deployment solutions to figure out what drivers that needs to download to each machine during install. It is a part of the SMBBios information and can be accessed using WMI, in WMIC it is called Name and Vendor and in PowerShell it is called Manufacturer and Model. Now, lets take a look.

The Old WMI Method:

Execute wmic csproduct get name,vendor from a CMD prompt.

image

The New POSH Method:

Execute Get-WmiObject Win32_ComputerSystem | Select Model,Manufacturer from a PowerShell prompt.

image

/mike

Posted in Deployment, Drivers, MDT, PowerShell, SCCM, WMI | Tagged: , , , | 4 Comments »

Step-by-Step: Upgrading BIOS during LiteTouch(ZeroTouch) Deployment, for Dell, Hewlett-Packard and Lenovo (v2)

Posted by Mikael Nystrom on December 16, 2013

Long time ago I wrote a post on how to upgrade the BIOS/Firmware during the deployment of a PC in the beginning of a TaskSequence, since then I have been hammered with the question on how to do the same thing but later on, when Windows is running, that has been nagging me, (which obviously paid off for all of you that has been doing that). My friends, here it is, this time in PowerShell, but hey, I don’t do XP anymore.

The basics

The basic Idea is to have a PowerShell script run that will discover what bios version we have and IF we have an update run the update according the that model’s specific way of running a firmware upgrade. It is also possible to just use the PowerShell script as a framework for other similar task of course, or you could use it to kick off something like SSM(HP) to do the job. I did one change, besides using PowerShell and that is to copy down the files to the local drive before running the upgrade, just to be sure that a messy network does not break the upgrade. The script is tested with a couple of HP’s, a Dell and a Lenovo, so there is of course no way I can guarantee it will work with every piece of PC around the globe, but hey, its PowerShell so you can modify it on your own :-). I also created it as an application for MDT LiteTouch, so you need to modify it slightly to run it in SCCM and it also needs the “AliasUserExit.vbs” script since I’m using ModelAlias and MakeAlias. If you don’t like that, just change the lines in he PowerShell code to use Make and Model or anything else that you can read from WMI using PowerShell

The PowerShell script (section One)

This part is just about creating log files, and getting basic data from the TaskSequence/TSEnviroment

image

The PowerShell script (section Two)

Here you can see the function that gets the SMBIOSBIOSVersion, and for all these vendors it is the same, but that could change in the future, so I decided to use the PowerShell Switch to figure out on how to get it. If you look close you can also see that I’m feeding back data to the TSEnviroment, that is not needed for this to work, but hey, you cannot get enough variables to play with, can you :-)

image

The PowerShell script (section three)

Here is when we get serious, you need to add every model that should be upgraded as a Switch Value and then update the $ExpectedBIOSVersion so it match what you should have. Then you need to add the BIOS update files in to the folder structure in the the Application and last you need to create/modify the UpgradeBIOS.cmd for each model so it runs whatever it is suppose to run to make magic happen.

image

The Folder Structure

Here you can see the folder structure, in this case HP Elitebook 8460p also has sub folders, whatever the vendors has a structure I put in the folder and that will then end up on the local drive, where I run the batch file.

image

The Application in MDT

Just a standard “app” in MDT, I don’t use the “Run PowerShell” script since Applications are easier to modify, move, export, import, and play with. But there should no very little work to get it to work as a script instead, basically the only thing you need to to is to store the script in a folder that the TS can reach, all the folder structure and the file copy is based on where the script is located.

image

CustomSettings.ini needs to be updated!

To figure out if a reboot is needed or not I added a reboot step and reads the property RebootNedeed, so you need to add that to customsettings.ini

image

The TaskSequence

As you can see, I did create a folder for this, easy to copy, easy to move, easy to enable/disable. The restart computer step does have a condition, it only executes if RebootNeeded is set to YES, which is set IF you run the BiosUpgrade.CMD batch file, in the PowerShell script I do return 3010 and I also set the RebootNeeded to YES.

image

The Restart computer Condition

image

 

How to?

  • Download the script
  • Unpack
  • Create a new Application in MDT (If you use SCCM or don’t like Apps, modify the script inside the folder first and add it as a script in the TS)
    • CommandLine: powershell.exe -ExecutionPolicy Unrestricted -File ViaMonstraUpgradeBios.ps1
  • Modify the script to fit your computers, versions and download each upgrade into each folder in the folder structure
  • Add it as an application
  • Enjoy

The Download

http://sdrv.ms/1ffLbji

/mike

The “old” Post: http://deploymentbunny.com/2011/05/20/step-by-step-upgrading-bios-during-litetouch-deployment-for-dell-hewlett-packard-and-lenovo/

The link to the AliasUserExit Script: http://deploymentbunny.com/2013/03/06/back-to-basiccustomsettings-inisample-2/

Posted in BIOS, Deployment, Firmware, MDT, SCCM | Tagged: | 2 Comments »

Nice to Know – Dumping MDT Monitor data to a Webpage (using PowerShell) – Update

Posted by Mikael Nystrom on December 13, 2013

A couple of days ago I published a simple PowerShell script that dumps the MDT monitoring data and convert it into a web page, the interest for that has been huge. The customer came back to me with one of those –Is it possible to…

They wanted to have the role that is assigned to the computer and that information is not in the MDT monitoring data output, but it is in the MDT database, so if I could read that using PowerShell and use the name from the MDT Monitoring as input, that should be doable. So I “sacrificed” the evening and now it is working, email the customer and the response was “Thank you!!”, so I thought maybe you would like to get the update to.

The new look! (including the Role information from the MDT database)

image

The new Script

image

The difference is:

Line 2 and 3:
  • I added the logic to connect to the DB
Line 11 – 15
  • I added logic to get the role from the DB
Line 42
  • I added Role in the select state
Line 49
  • I added Role in the select state

That’s all

/mike

Download the script: http://sdrv.ms/1hRSMZv

Read about the original post here: http://deploymentbunny.com/2013/12/09/nice-to-know-dumping-mdt-monitor-data-to-a-webpage-using-powershell/

Read about Sean O’Mahony’s ”branding/styling” here : http://mentalseepage.wordpress.com/2013/12/12/output-mdt-monitor-tab-to-webpage/

Read about getting the MDT Monitor to work in SCCM here: http://www.deploymentresearch.com/Research/tabid/62/EntryId/131/Adding-DaRT-8-1-from-MDOP-2013-R2-to-ConfigMgr-2012-R2.aspx

Read about the PowerShell module for MDT here: http://blogs.technet.com/b/mniehaus/archive/2009/07/09/3241504.aspx

Posted in Deployment, MDT, PowerShell, SCCM | Tagged: , , | 6 Comments »

Nice to Know – Dumping MDT Monitor data to a Webpage (using PowerShell)

Posted by Mikael Nystrom on December 9, 2013

(update – http://deploymentbunny.com/2013/12/13/nice-to-know-dumping-mdt-monitor-data-to-a-webpage-using-powershell-update/)

A customer asked me –Could you create like a web page that shows the same info as the MDT monitoring tab, so can see all the deployment all the time?, the answer is of course –Yes, of course you can!

Now, before you start barking at me and say “That could be done much easier using C#, Lisp, VB.Net” or something, this was the “My-flight-leaves-very-soon” kind of coding, so it jus a very simple PowerShell snip that runs on a 5 min schedule and create a new page and the result looks like this:

image

The script will read the data from the MDT monitoring feed, so the web server does not need to be on the server it self, it does not require anything at all, the script generates a HTML page and the we “modify” it on the fly and the save it in the inetpub folder, and here is the code:

image

And in text form:

$URL = "http://EDUDEPLOY09:9801/MDTMonitorData/Computers"

function GetMDTData { 
  $Data = Invoke-RestMethod $URL

  foreach($property in ($Data.content.properties) ) { 
    New-Object PSObject -Property @{ 
      Name = $($property.Name); 
      PercentComplete = $($property.PercentComplete.’#text’); 
      Warnings = $($property.Warnings.’#text’); 
      Errors = $($property.Errors.’#text’); 
      DeploymentStatus = $( 
        Switch ($property.DeploymentStatus.’#text’) { 
        1 { "Active/Running" } 
        2 { "Failed" } 
        3 { "Successfully completed" } 
        Default { "Unknown" } 
        } 
      ); 
      StartTime = $($property.StartTime.’#text’) -replace "T"," "; 
      EndTime = $($property.EndTime.’#text’) -replace "T"," "; 
    } 
  } 
} 

$Head = "<style>"
$Head = $Head + "BODY{background-color:peachpuff;}"
$Head = $Head + "TABLE{border-width: 2px;border-style: solid;border-color: black;border-collapse: collapse;}"
$Head = $Head + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
$Head = $Head + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black}"
$Head = $Head + "</style>"

$Title = "LabCenter Deployment Status"

GetMDTData | Select Name, DeploymentStatus, PercentComplete, Warnings, Errors, StartTime, EndTime | Sort -Property Name |
ConvertTo-Html  `
-Title $Title  `
-Head $Head  `
-Body (Get-Date -UFormat "%Y-%m-%d - %T ")  `
-PreContent "<H2>LabCenter Deployment Status for: $ENV:COMPUTERNAME </H2><P>Generated by Power of the Force</P>"  `
-PostContent "<P>For details, contact support@truesec.se.</P>"  `
-Property Name,DeploymentStatus,PercentComplete,Warnings,Errors,StartTime |
ForEach {
if($_ -like "*<td>Successfully completed</td>*"){$_ -replace "<tr>", "<tr bgcolor=green>"}
elseif($_ -like "*<td>Failed</td>*"){$_ -replace "<tr>", "<tr bgcolor=red>"}
else{$_}
} > C:\inetpub\wwwroot\default.htm 
#Invoke-Item $ENV:TEMP\Default.htm

And as a download of course http://sdrv.ms/J4ttVC

/mike

Posted in Deployment, MDT, PowerShell, SCCM | Tagged: , , | 13 Comments »

Nice to know – Put Office365 Click To Run in the Ref Image using MDT 2013

Posted by Mikael Nystrom on December 8, 2013

A while ago I did a session regarding Office 365 and during that session I promised to publish the script and keeping promises is a good thing I have been told. Office 365 is basically a prepackaged app-v package on steroids and in many cases it is a smart thing to put it into the ref image, that way the user don’t need to download it, not that its very complicated, but not all users like the idea of start a brand new morning with installing a bunch of apps, just to be able to do something useful. So here is.

How does the script work?

First it will create a destination folder, next up it will copy the install files down to the local computer and that is very important, the install process will change after a while and when it change it also change the process that runs the installer, so to avoid all kinds of issues around permissions, it is easier to run it from the local drive.

How do I use it?

Well, I will assume you use MDT 201X and in that case, just create a folder called “Install – Office 365”, in that folder create the folder Source and in that folder download and store you copy of office 365 (You need to run a special download application – Office Deployment Tool) and also modify the XML file BEFORE you run setup to download, otherwise you will most likely download everything ELSE BUT Office365 click to run, check out the XML file config here http://technet.microsoft.com/en-us/library/jj219426.aspx

Here is a sample that I use when running demos:

image

You might notice that I store the log file in the OSDLogs folder and the reason is that it will then be copied amongs the other log files specified using SLShare in customsettings.ini

The last step is to create a standard application in MDT 201X and pointing to that folder, then you add the setup command:

image

 

Here is the download link to the script http://sdrv.ms/1cjt2h8

/mike

Posted in Deployment, MDT, Office 365 | Tagged: | 1 Comment »

Microsoft Deployment Toolkit 2013 is here

Posted by Mikael Nystrom on October 18, 2013

Download from http://www.microsoft.com/en-us/download/details.aspx?id=40796

Microsoft Deployment Toolkit (MDT) 2013 is a Solution Accelerator for operating system and application deployment. MDT 2013 supports deployment of Windows 8.1, Windows 8, Windows 7, Windows Server 2012 R2, Windows Server 2012, and Windows Server 2008 R2.
Feature Summary

  • Deploy Windows and Office with Microsoft Deployment Toolkit 2013. MDT is the recommended process and toolset for automating desktop and server deployment. MDT provides you with the following benefits:
  • Unified tools and processes, including a set of guidance, for deploying desktops and servers in a common deployment console.
  • Reduced deployment time and standardized desktop and server images

Some of the key changes in MDT 2013 are:

  • Support for the Windows Assessment and Deployment Kit (ADK) for Windows 8.1.
  • Support for deployment of Windows 8.1 and Windows Server 2012 R2.
  • Support for System Center 2012 R2 Configuration Manager.
  • Improved support x86-based Unified Extensible Firmware Interface (UEFI) systems.

Happy deployment my friends

/mike

Posted in Deployment, MDT, System Center 2012 R2 | Tagged: | 2 Comments »

 
Follow

Get every new post delivered to your Inbox.

Join 2,347 other followers