The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

Archive for the ‘MDT’ Category

PowerShell is King – Building a Reference Image Factory (v 3.2)

Posted by Mikael Nystrom on February 23, 2017

The Image Factory has been re-worked and updated. It also has moved to GitHub https://github.com/DeploymentBunny/ImageFactoryV3ForHyper-V/

Concept and flow

The idea is the same, we use MDT, create refimages task sequences that runs without any questions. A PowerShell script will grab all enabled Task Sequences in a specified folder, create a VM for each of them. Grab the Bios Serial number from each om them, update customsettings ini with that information, start the VM’s (number of concurrent VM’s determine how many VM’s can run at the same time, wait until all VM’s are done and finally removes all VM’s for a cleanup process. You can run the script as is (if you store it in C:\Setup\ImageFactoryV3ForHyper-V on you MDT server), or you can open it in ISE and run section by section to see what happens.

The XML file (C:\Setup\ImageFactoryV3ForHyper-V\ImageFactoryV3.xml)

Is a control file for settings, pretty straightforward, just make sure that all values are correct.

image

The Script C:\Setup\ImageFactoryV3ForHyper-V\ImageFactoryV3-Build.ps1

The script contains some functions and logic, each section is described so you do know what it does. There are switches to the script,

  • -UpdateBootImage
  • -EnableMDTMonitoring
  • -TestMode

UppdateBoot image $True, updates the bootimage before copy, EnableMDTMonitoring require that MDT monitoring is enabled of the deployment share and testmode is not yet working (I’ll get back on that)

image

The PSINI Module

One big change is that instead of using a hack, (using KVP) I switched over to use a module called PSINI, it basically turns customsettings.ini into a hash table, making it easy to configure using PowerShell. That also means you need to download that module from TechNet Gallery http://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91and all credit for that module goes to http://oliver.lipkau.net/blog

Have Fun

/Mike

Posted in MDT, PowerShell, Reference Image | Tagged: , , | 24 Comments »

OSD – Conditional disk layout (based on model)

Posted by Mikael Nystrom on February 10, 2017

A while back I did an online training for Penton Tech https://education.pentontechnology.com/courses/deploying-windows-10-os-using-microsoft-deployment-toolkit on Windows 10 OS Deployment. One of the attendees had a question (you know who you are).

– Is it possible to format and partition differently, based on what model I’m deploying?

Yes, you can have different disk layout/partitioning/volumes, based on anything, and that includes the model of the computer. I use this when deploying servers and client to have different partition schemas on virtual machines, I do not need to have the recovery partition in the end of the virtual disk, I don’t really “repair” a Virtual Machine the same way as i recover a physical machine, and you should not.

So, how do you do this?

Open your task sequence and modify the New Computer step like this.

image
The modified Task Sequence.

In this Task Sequence there are three different group’s, one for virtual machines, one for HP ZBook Studio G3 and the last one for everything else.

The modification starts under Validate, the first step after that sets DiskDone=NO, next step is the Group named Virtual Machine with the following conditions set:

image
Conditions on the group Virtual Machine.

The the group is executed if the Model is ‘Virtual Machine’ and DiskDone is NOT set to YES, so basically if it is a Virtual Machine it will partition/format according to the steps in the group. In the end of the group it will set DiskDone to YES, that way we know the disks are done and we can use that to prevent the following partitioning steps from running. Let us check the next step:

image 
Conditions on the group HP ZBook Studio G3.

This step is the same as the step for Virtual Machine with one difference, in this case it only runs when the Model is a HP ZBook Studio G3. Let us check the last step:

image
Conditions on the group All others.

The last groups executes on any device, as long as DiskDone is NOT set to YES.

The Result.

Here is the result when running this in a Virtual Machine:

image

Here is the result when running this on a HP:

image

Here is a plain vanilla install:

image

Have fun!

/mike

Posted in Lite Touch, MDT, OS Deployment, OSD | Tagged: , , , | Leave a Comment »

OSD – Add information to the Computer during OSD using a Custom Tattoo Step

Posted by Mikael Nystrom on December 2, 2016

When using an MDT (integrated in ConfigMgr or standalone) there is a step called Tattoo, this step will write information to the registry as well as to the WMI repository.

Let us see what it looks by default:

Get-WMIObject –Class Microsoft_BDD_Info

image
Result.

Get-Item -Path ‘HKLM:\SOFTWARE\Microsoft\Deployment 4’

image

Cool, but I need my own stuff?

We have done this for various  reasons and many customers, it could be used for making sure the computer ends up in certain ConfigMgr Collections, or that applications behave in a certain way, or that the asset management tools does the job differently, or that the correct support team can know what the computer was configured for, or what task sequence that was used, or…. As you see the are some valid reasons for this, no doubt.

The question is of course, should you modify the existing ZTITatto.wsf and corresponding .MOF file?, No, you should not do that, instead you should create new files and use them instead.

So, here is the download : https://github.com/DeploymentBunny/Files/tree/master/Tools/Custom-ZTITatoo

To make the work in a task sequence you need to add the files to you Scripts folder, update the CustomSettings.ini if you are using Custom Properties and add a step in the Task Sequence.

Here is a sample of CustomSettings.ini

image

I have added 4 new properties, added them to a MacAddress, so first step is to verify that the ZTIGather process reads this correct, let us verify this by running:

cscript \\redepl01\mdtproduction$\Scripts\ZTIGather.wsf /inifile:c:\Temp\CustomSettings.ini

image
Result after running the following command to perform the inventory.

Now, lets run the custom tattoo script:

cscript \\redepl01\mdtproduction$\Scripts\ViaMonstraTatoo.wsf

image
That looks great!

Now, let us verify that we get the correct data from WMI and Registry:

First, get the WMI repository:

Get-WmiObject -Class ViaMonstra_Info

image
The WMI repository was updated.

Let us check the Registry:

Get-Item -Path ‘HKLM:\SOFTWARE\ViaMonstra\OSD’

image
The Registry was updated.

At LabCenter

The Customer LabCenter deploys computer for hands-on labs and they wanted each computer to be tattooed with information regarding the LAB and one thing they use it for is to be able to display the information directly in the screen using BGinfo, but they also use it for other purposes. BGInfo reads the Registry values, or WMI

image

How to change my own stuff then?

Download the files from:https://github.com/DeploymentBunny/Files/tree/master/Tools/Custom-ZTITatoo and edit the scripts, (.wsf and .mof) by replacing the values that are in use, like

  • ViaMonstra
  • ViaRole
  • ViaClass
  • ViaOwner
  • ViaTag

Save, and verify

/mike

Posted in ConfigMgr, Lite Touch, MDT, OSD, Zero Touch | Tagged: , , , , | 5 Comments »

OSD – Microsoft Deployment Toolkit Build 8443 is out

Posted by Mikael Nystrom on November 14, 2016

Today a new version of MDT was released, the main reason is Quality Updates and full support for Windows Server 2016 as well as Windows 10 1607. It does require ADK 1607. If you are using MDT in your OS deployment solution, go ahead, download, read, update and enjoy live.

image

/mike

Posted in MDT, OSD | Tagged: , | 2 Comments »

OSD – BIOS upgrade during OS Deployment in MDT/ConfigMgr (v3)

Posted by Mikael Nystrom on July 20, 2016

This is the third version of the script solution; it is very simple. You detect make/model in any way you would like to, create a rule based on BIOS version, if the rule match, nothing happens, otherwise it runs any command you want. That said, you could use this for other task as well. Most common question is “does it work with any Make/Model”`No, there are some vendors that does not provide the ability to run a BIOS upgrade silently without reboot without control, that is, the darn thing reboots immediately and that usually breaks the Task Sequence. I have one thing for those vendors to say “Shame on you!”

here are older posts on the subject

https://deploymentbunny.com/2011/05/20/step-by-step-upgrading-bios-during-litetouch-deployment-for-dell-hewlett-packard-and-lenovo/

https://deploymentbunny.com/2013/12/16/step-by-step-upgrading-bios-during-litetouchzerotouch-deployment-for-dell-hewlett-packard-and-lenovo-v2/

Detect the Model

The detection in the script is actually whatever you want, it is just a “If-then”  here are two sample lines detection that you will find in the script

if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP EliteBook 8560w'){}
if($ModelAlias -eq 'HP EliteBook 8460p'){}

Use the detection method for each model you like, very simple

Detect the BIOS version

This is also not that hard, here are 2 sample lines from the script

if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCF Ver. F.63'){}
if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '786G1 v01.27'){}

Store the upgrade files

The upgrade files are stored with the model name, like this:

image

The Silent Command

You also need to figure out the command, not really hard, download the bios upgrade, read how to run it from a command line, update the script and you are done, here is a sample of one of those sections.

$Exe = 'hpqflash.exe'
$Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
$Executable = $Location + "\" + $exe
Set-Location -Path $Location
Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCE.CAB" –Verbose

Run the script

in MDT you can import the folder with the script as a application and set this as the command line:

PowerShell.exe -ExecutionPolicy Bypass -File Install-BIOSUpgrade.ps1

In ConfigMgr you can import this as a Package and then run the command line the same way

It is also possible to run this outside of a task sequence if you like, it works as a stand alone script, however, you cannot use the integration with MDT of course.

If you want it is possible to add a custom property in customsettings.ini, something like “NeedReboot”, then you can add the following to happen if the BIOS has been upgraded

$tsenv.Value(“NeedReboot”) = “YES”

If you then in the step after this, set a condition on a reboot step, well then it will reboot when needed, otherwise not, you can read about that in one of my old postings here

https://deploymentbunny.com/2013/12/16/step-by-step-upgrading-bios-during-litetouchzerotouch-deployment-for-dell-hewlett-packard-and-lenovo-v2/

The result

BiosUpgradeResult
It was needed.

BiosUpgradeResultNotNeeded
It was not needed.

The Script


Function Import-SMSTSENV{
    try
    {
        $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
        Write-Output "$ScriptName - tsenv is $tsenv "
        $MDTIntegration = "YES"
        
        #$tsenv.GetVariables() | % { Write-Output "$ScriptName - $_ = $($tsenv.Value($_))" }
    }
    catch
    {
        Write-Output "$ScriptName - Unable to load Microsoft.SMS.TSEnvironment"
        Write-Output "$ScriptName - Running in standalonemode"
        $MDTIntegration = "NO"
    }
    Finally
    {
    if ($MDTIntegration -eq "YES"){
        $Logpath = $tsenv.Value("LogPath")
        $LogFile = $Logpath + "\" + "$ScriptName.log"

    }
    Else{
        $Logpath = $env:TEMP
        $LogFile = $Logpath + "\" + "$ScriptName.log"
    }
    }
}
Function Start-Logging{
    start-transcript -path $LogFile -Force
}
Function Stop-Logging{
    Stop-Transcript
}
Function Invoke-Exe{
    [CmdletBinding(SupportsShouldProcess=$true)]
 
    param(
        [parameter(mandatory=$true,position=0)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Executable,
 
        [parameter(mandatory=$false,position=1)]
        [string]
        $Arguments
    )
 
    if($Arguments -eq "")
    {
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -NoNewWindow -Wait -Passthru
    }else{
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru
    }
    Write-Verbose "Returncode is $($ReturnFromEXE.ExitCode)"
    Return $ReturnFromEXE.ExitCode
}

# Set vars
$SCRIPTDIR = split-path -parent $MyInvocation.MyCommand.Path
$SCRIPTNAME = split-path -leaf $MyInvocation.MyCommand.Path
$SOURCEROOT = "$SCRIPTDIR\Source"
$SettingsFile = $SCRIPTDIR + "\" + $SettingsName
$LANG = (Get-Culture).Name
$OSV = $Null
$ARCHITECTURE = $env:PROCESSOR_ARCHITECTURE

#Try to Import SMSTSEnv
. Import-SMSTSENV

# Set more vars
$Make = $tsenv.Value("Make")
$Model = $tsenv.Value("Model")
$ModelAlias = $tsenv.Value("ModelAlias")
$MakeAlias = $tsenv.Value("MakeAlias")

#Start Transcript Logging
. Start-Logging

#Output base info
Write-Output ""
Write-Output "$ScriptName - ScriptDir: $ScriptDir"
Write-Output "$ScriptName - SourceRoot: $SOURCEROOT"
Write-Output "$ScriptName - ScriptName: $ScriptName"
Write-Output "$ScriptName - Current Culture: $LANG"
Write-Output "$ScriptName - Integration with MDT(LTI/ZTI): $MDTIntegration"
Write-Output "$ScriptName - Log: $LogFile"
Write-Output "$ScriptName - Model (win32_computersystem): $((Get-WmiObject Win32_ComputerSystem).model)"
Write-Output "$ScriptName - Name (Win32_ComputerSystemProduct): $((Get-WmiObject Win32_ComputerSystemProduct).Name)"
Write-Output "$ScriptName - Version (Win32_ComputerSystemProduct): $((Get-WmiObject Win32_ComputerSystemProduct).Version)"
Write-Output "$ScriptName - Model (from TSENV): $Model"
Write-Output "$ScriptName - ModelAlias (from TSENV): $ModelAlias"

#Check Model
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP EliteBook 8560w'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SVD Ver. F.50'){
        Write-Output "Needs upgrade"
        $Exe = 'hpqflash.exe'
        $Location = "$SCRIPTDIR\Source\HP EliteBook 8560w"
        $Executable = $Location + "\" + $exe
        Set-Location -Path $Location
        Invoke-Exe -Executable "$Executable" -Arguments "/s /p LCadmin1.bin" -Verbose
    }
    else
    {
        Write-Output "No Need to upgrade"
    }
}
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP ProBook 6570b'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*ICE*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68ICE Ver. F.62'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP ProBook 6570b"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68ICE.cab" -Verbose
        }
        else
        {
            Write-Output "No Need to upgrade"
        }
    }
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*ICF*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68ICF Ver. F.62'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP ProBook 6570b"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68ICF.cab" -Verbose
        }
        else
        {
            Write-Output "No Need to upgrade"
        }
    }
}
if($ModelAlias -eq 'HP EliteBook 8460p'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*SCF*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCF Ver. F.63'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCF.CAB" -Verbose
            }
        else
            {
            Write-Output "No Need to upgrade"
        }
    }
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -Like '*SCE*'){
        if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '68SCE Ver. F.63'){
            Write-Output "Needs upgrade"
            $Exe = 'hpqflash.exe'
            $Location = "$SCRIPTDIR\Source\HP EliteBook 8460p"
            $Executable = $Location + "\" + $exe
            Set-Location -Path $Location
            Invoke-Exe -Executable "$Executable" -Arguments "/s /f 68SCE.CAB" -Verbose
            }
        else
            {
            Write-Output "No Need to upgrade"
        }
    }
}
if($((Get-WmiObject Win32_ComputerSystem).model) -eq 'HP Compaq dc7900 Small Form Factor'){
    Write-Output "Model is $((Get-WmiObject Win32_ComputerSystem).model)"
    Write-Output "Checking BIOS Version"
    Write-Output "Version is $((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion)"
    if($((Get-WmiObject Win32_Bios).SMBIOSBIOSVersion) -ne '786G1 v01.27'){
        Write-Output "Needs upgrade"
        $Exe = 'hpqflash.exe'
        $Location = "$SCRIPTDIR\Source\HP Compaq dc7900 Small Form Factor\HPQFlash"
        $Executable = $Location + "\" + $exe
        $SourceFile = $Location + "\" + "Password01.bin"
        $Destination = $env:TEMP
        $DestinationFile = $Destination + "\" + "Password01.bin"
        Copy-Item -Path $SourceFile -Destination $DestinationFile -Force -Verbose 
        Set-Location -Path $Location
        Invoke-Exe -Executable $Executable -Arguments "/s /p $DestinationFile"
    }
    else
    {
        Write-Output "No Need to upgrade"
    }
}

#Stop Logging
. Stop-Logging


/mike

Posted in BIOS, ConfigMgr, MDT, OS Deployment, OSD, PowerShell | Tagged: , , , , , | 5 Comments »

OSD – The future of MDT is going to be PowerShell!

Posted by Mikael Nystrom on May 18, 2016

At MMSmoa today, Michael Niehaus presented a new approach for MDT, the shift from VBscript to PowerShell. They idea is to get the code up on GitHub. The basic engine and framework will be done, but it will allow for contributors to test and verify and even provide suggestions.

You can check it out here: https://github.com/mtniehaus/PSD

The New Task Sequence:

image

image

The Install App Step:

image

/mike

Posted in MDT | Tagged: | 6 Comments »

OSD – Export drivers using a task sequence in Lite Touch and some PowerShell

Posted by Mikael Nystrom on May 18, 2016

Yesterday i did a demo of a Task Sequence I use to extract drivers from a computer that already have all drivers correctly installed, could be a system that I need to reinstall, or a new machine with fairly new drivers installed. The Task Sequence basically grabs information from the computer, such as Operating System, Architecture and Model or Modelalias, grabs the drivers and copy them to the deployment share. I can then import the drivers to a ConfigMgr package or use them in LiteTouch for deployment.

The script is fairly simple and easy to change to fit in your environment.

The Task Sequence

It contains 3 steps, a gather step to get the inventory of the machine correctly, a set finish action to avoid reboot if your are using finish action in customsettings.ini and the application that grabs the drivers. Since it is a application this task sequence works only when Windows is running, not in WinPE.

image
The Task Sequence.

The Application

The Script runs as an application, so you need to download the script to a folder and then import it as an application with following settings:

PowerShell.exe -ExecutionPolicy Bypass -File ExportDrivers.ps1

image
The Extract Drivers Application in Deployment Workbench.

The Script

The PowerShell script is a generic script I use a s “wrapper”, so it does have functions that is not really needed in this scenario, so it is possible to make it shorter if you for any reason want that. The script detects if it has been invoked from a task sequence or not, if it has, it will create a path based on deployment root, Operating System, Architecture and ModelAlias (If you don’t use ModelAlias UserExit, start to do that or change to Model in the script), otherwise it will export the drivers to C:\ExportedDrivers

The active part of the script looks like this:

image
The active part of the script.

Note that it will delete all drivers that begins with PRN. That is printer drivers and I usually do not want them.

ExportDrivers.ps1

<#
 Install Wrapper 1.0
 Author: Mikael Nystrom
 http://www.deploymentbunny.com 
#>
 
Function Invoke-Exe{
    [CmdletBinding(SupportsShouldProcess=$true)]
 
    param(
        [parameter(mandatory=$true,position=0)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Executable,
 
        [parameter(mandatory=$false,position=1)]
        [string]
        $Arguments
    )
 
    if($Arguments -eq "")
    {
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -NoNewWindow -Wait -Passthru
    }else{
        Write-Verbose "Running $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru"
        $ReturnFromEXE = Start-Process -FilePath $Executable -ArgumentList $Arguments -NoNewWindow -Wait -Passthru
    }
    Write-Verbose "Returncode is $($ReturnFromEXE.ExitCode)"
    Return $ReturnFromEXE.ExitCode
}
Function Get-OSVersion([ref]$OSv){
    $OS = Get-WmiObject -class Win32_OperatingSystem
    Switch -Regex ($OS.Version)
    {
    "6.1"
        {If($OS.ProductType -eq 1)
            {$OSv.value = "Windows 7 SP1"}
                Else
            {$OSv.value = "Windows Server 2008 R2"}
        }
    "6.2"
        {If($OS.ProductType -eq 1)
            {$OSv.value = "Windows 8"}
                Else
            {$OSv.value = "Windows Server 2012"}
        }
    "6.3"
        {If($OS.ProductType -eq 1)
            {$OSv.value = "Windows 8.1"}
                Else
            {$OSv.value = "Windows Server 2012 R2"}
        }
    "10."
        {If($OS.ProductType -eq 1)
            {$OSv.value = "Windows 10"}
                Else
            {$OSv.value = "Windows Server 2016"}
        }
    DEFAULT { "Version not listed" }
    } 
}
Function Import-SMSTSENV{
    try
    {
        $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
        Write-Output "$ScriptName - tsenv is $tsenv "
        $MDTIntegration = "YES"
         
        #$tsenv.GetVariables() | % { Write-Output "$ScriptName - $_ = $($tsenv.Value($_))" }
    }
    catch
    {
        Write-Output "$ScriptName - Unable to load Microsoft.SMS.TSEnvironment"
        Write-Output "$ScriptName - Running in standalonemode"
        $MDTIntegration = "NO"
    }
    Finally
    {
    if ($MDTIntegration -eq "YES"){
        $Logpath = $tsenv.Value("LogPath")
        $LogFile = $Logpath + "\" + "$ScriptName.log"
 
    }
    Else{
        $Logpath = $env:TEMP
        $LogFile = $Logpath + "\" + "$ScriptName.txt"
    }
    }
}
Function Start-Logging{
    start-transcript -path $LogFile -Force
}
Function Stop-Logging{
    Stop-Transcript
}
 
# Set Vars
$SCRIPTDIR = split-path -parent $MyInvocation.MyCommand.Path
$SCRIPTNAME = split-path -leaf $MyInvocation.MyCommand.Path
$SOURCEROOT = "$SCRIPTDIR\Source"
$LANG = (Get-Culture).Name
$OSV = $Null
$ARCHITECTURE = $env:PROCESSOR_ARCHITECTURE
 
#Try to Import SMSTSEnv
. Import-SMSTSENV
 
#Start Transcript Logging
. Start-Logging
 
#Detect current OS Version
. Get-OSVersion -osv ([ref]$osv) 
 
#Output base info
Write-Output ""
Write-Output "$ScriptName - ScriptDir: $ScriptDir"
Write-Output "$ScriptName - SourceRoot: $SOURCEROOT"
Write-Output "$ScriptName - ScriptName: $ScriptName"
Write-Output "$ScriptName - OS Name: $OSV"
Write-Output "$ScriptName - OS Architecture: $ARCHITECTURE"
Write-Output "$ScriptName - Current Culture: $LANG"
Write-Output "$ScriptName - Integration with MDT(LTI/ZTI): $MDTIntegration"
Write-Output "$ScriptName - Log: $LogFile"
 
if($MDTIntegration -eq "YES"){
    $RootFolder = $tsenv.Value("Deployroot")
    $Arch = $tsenv.Value("Architecture")
    $Model = $tsenv.Value("ModelAlias")
    $Path = $RootFolder + "\Drivers\" + $OSV + "\" + $Arch + "\" + $Model
}
else{
    $Path = "C:\ExportedDrivers"
}

Write-Output "$ScriptName - Driver export path: $Path"

#Export Drivers
Export-WindowsDriver -Destination $Path -Online -Verbose

#Get Printer Drivers
Get-ChildItem -Path $Path -Filter PRN* -Directory | Remove-Item -Force -Recurse

. Stop-Logging

/mike

Posted in Lite Touch, MDT, OS Deployment, OSD | Tagged: , , , | 6 Comments »

OSD – In MDT 2013 Update 2–Sometimes “WimSplit” works and sometimes not

Posted by Mikael Nystrom on May 11, 2016

and i do not like “sometimes”. The need for WimSplit is big, the most common reason is to install Windows on a UEFI based machine. In that case the boot media must be FAT32 and a single file cannot be larger then 4095 MB, but a plain vanilla Windows Server 2016 is bigger, so…

The fix

Make sure that the operating system name ends with .WIM

image

Make sure that the Settings.XML file in the Deployment share\Control folder has the following setting:

image

And, look it is working…

image

/mike

Posted in MDT, OS Deployment, OSD | Tagged: , , | 8 Comments »

OS Deployment – Using the PowerShell to work with the MDT Database module: Sample 1

Posted by Mikael Nystrom on April 22, 2016

During the OSD class in Phoenix this week we worked with the MDT Database and some one asked if it was possible to use PowerShell to modify the database and and the same time verify if the mac address or the computer name was already in use before creating the database entry. The short answer was –Yes, of course. So I decided to create a sample on how that could look like.

Working with the database is pretty simple using the PowerShell module that Michael Niehaus created https://blogs.technet.microsoft.com/mniehaus/2009/05/14/manipulating-the-microsoft-deployment-toolkit-database-using-powershell/

So, using that module and the Active Directory PowerShell module means that we can now check if the Mac Address is already in use or if the computer name already exists in the MDT database or in Active Directory. The PowerShell script sample is using regex to verify that Mac Address as well as the computer name. Besides creating the object if it does not exist (or you can use the –Force switch to override) it also adds a database role to the computer.

Note: That you should also fix the database, since it is broken by default, just follow these steps: https://syscenramblings.wordpress.com/2016/01/15/mdt-database-the-powershell-module-fix/

The Script:


#Add Computer to the MDT Database 1.0
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
    [ValidateLength(3,16)]
    [ValidatePattern('[A-Z][0-9]')]
    [String]$ComputerName,

    [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
    [ValidateSet('Standard PC','RnD','Admin Workstation')] 
    [String]$Role,

    [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 
    [ValidatePattern('^([0-9a-fA-F]{2}[:-]{0,1}){5}[0-9a-fA-F]{2}$')]
    [String]$MacAddress,

    [Switch]$Force
)

#Import the Modules and connect to the database
Import-Module MDTDB -ErrorAction Stop
Import-Module ActiveDirectory -ErrorAction Stop
Connect-MDTDatabase -sqlServer MDT01 -database MDT01 -instance SQLExpress -ErrorAction stop

#Create function for check AD if name exists
Function CheckIfComputerInADExists{
    Param(
        $ComputerName
    )
    try {
        $Null = Get-ADComputer $ComputerName
        Return $True
    }
    Catch {
        Return $False
    }
}

#Create function for check MDT DB if name exists
Function CheckIfComputerInMDTExists{
    Param(
        $ComputerName
    )
    $result = Get-MDTComputer | Where-Object -Property OSDComputerName -EQ -Value $ComputerName
    if($result -ne $null){Return $True}else{$False}
}

#Create function for check MDT DB if MAC exists
Function CheckIfMacAddressInMDTExists{
    Param(
        $MacAddress
    )
    $result = Get-MDTComputer -macAddress $MacAddress
    if($result -ne $null){Return $True}else{$False}
}

#Check if Computer exists in Active Directory
$CheckAD = CheckIfComputerInADExists -ComputerName $ComputerName
if($CheckAD -eq $true){
    Write-Warning "$ComputerName exists in Active Directory"
    if(!($Force)){BREAK}
    }else{Write-Host "AD Name check OK"}

#Check if Computer exists in the MDT database
$CheckMDT = CheckIfComputerInMDTExists -ComputerName $ComputerName
if($CheckMDT -eq $true){
    Write-Warning "$ComputerName exists in the MDT database"
    if(!($Force)){BREAK}
    }else{Write-Host "MDT name check OK"}

#Check if MacAddress exists in the MDT database
$CheckMAC = CheckIfMacAddressInMDTExists -MacAddress $MacAddress
if($CheckMAC -eq $true){
    Write-Warning "$MacAddress exists in the MDT database"
    if(!($Force)){BREAK}
    }else{Write-Host "MDT macaddress check OK"}

#Create array for all settings the computer should have
$Settings = @{
OSInstall='YES';
OSDComputerName="$ComputerName"
}

#If computer name exists and we used the -Force switch, remove it
if($CheckMDT -eq $true){
    Get-MDTComputer -description $ComputerName | Remove-MDTComputer
    }

#If MacAddress exists and we used the -Force switch, remove it
if($CheckMAC -eq $true){
    Get-MDTComputer -macAddress $MacAddress | Remove-MDTComputer
    }

#Create Computer in MDT Database
$NewMDTComputer = New-MDTComputer -macAddress $MacAddress -description $ComputerName -settings $Settings

#Add role to Computer in MDT Database
$NewMDTComputer | Set-MDTComputerRole -roles $Role


/mike

Posted in MDT, OS Deployment, OSD, PowerShell | Tagged: , , , | Leave a Comment »

OSD – Update your boot image on all PXE servers with one PowerShell script (LiteTouch)

Posted by Mikael Nystrom on March 9, 2016

Working at a customer (you know who you are) I asked

– How do you update all PXE\WDS servers around the globe?

– We logon and update them

– Would you like to have script that does that?

– Yes

So, here it is:


$Servers = "server1","Server2","Server3","Server4"
Foreach($Server in $Servers){
    wdsutil.exe /Verbose /Progress /Replace-Image /Image:"Lite Touch Windows PE (x86)" /Server:$Server /ImageType:Boot /Architecture:x86 /ReplacementImage /ImageFile:"D:\MDTProduction\Boot\LiteTouchPE_x86.wim" 
    wdsutil.exe /Verbose /Progress /Replace-Image /Image:"Lite Touch Windows PE (x64)" /Server:$Server /ImageType:Boot /Architecture:x64 /ReplacementImage /ImageFile:"D:\MDTProduction\Boot\LiteTouchPE_x64.wim" 
}

/mike

Posted in MDT, OS Deployment, OSD | Tagged: , | Leave a Comment »