The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

Archive for the ‘OS Deployment’ Category

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 – Deploying Windows Server 2016 NANO using Microsoft Deployment Toolkit

Posted by Mikael Nystrom on January 31, 2017

The “Gandalf” of Windows Operating System has done it once again, I’m talking about Michael Niehaus of course. He has created a package for MDT Build 8443 that enables you to deploy NANO Server using MDT, including Domain Join.

image

Here is the link to the post. https://blogs.technet.microsoft.com/mniehaus/2017/01/11/deploying-nano-server-using-mdt/

Happy Deployment

/mike

Posted in NANO, OS Deployment, OSD, Windows Server 2016 | Tagged: , , , | Leave a Comment »

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: , , , , , | 4 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 »

OSD – Prevent Windows to “randomly” run Windows Update during the creation of a reference image

Posted by Mikael Nystrom on May 10, 2016

You should absolutely have patches installed in your reference image, no question about the. The default setting in Microsoft Deployment Toolkit is to run Windows Update “when needed” and the default behavior is the same, so basically Windows will run Windows Update when it “feels” for it. When the machine is managed it is controlled, but a reference image is created when the operating system is unmanaged. This could result in all kinds of issues, it could result in a pending reboot “sometimes” or failure to install software “sometimes”. I don’t like “sometimes” or random…

Turn of random Windows Updates during reference image creation

It is actually very easy, you need to change “Protect Your PC” from 1 to 3

image
All settings for ProtectYourPC.

If you open the unattend.xml file in Windows System Image Manager it looks like this:

image
ProtectYourPC is now set to 3.

This way Windows Update will performed manually or since you are using MDT and LiteTouch as your tool to create the reference image, the two Windows Update steps will do the updates and no more “random” updates.

image
The two Windows Update steps in the LTI task sequence.

/mike

Posted in OS Deployment, OSD | Tagged: , | 16 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 »

Working in the Datacenter – Deploying HP Servers and configure BIOS for High Performance using PowerShell

Posted by Mikael Nystrom on March 8, 2016

If you have a HP ProLiant Gen 8 or Gen 9 it is possible to use PowerShell to configure the BIOS. One of the items I really like to configure is the Power Settings, in most cases you would like to have “performance” but the default setting is usually set in “Tree Hugging Mode” (also called power saving). This is especially true if server is going to be used as a Compute server (running Hyper-V).

You can read the previous posts here:

https://deploymentbunny.com/2016/03/07/working-in-the-datacenter-hp-bios-cmdlets-for-windows-powershell-x64/

https://deploymentbunny.com/2016/03/07/working-in-the-datacenter-application-wrapper-for-hp-bios-cmdlets-deploy-it-during-osd/

The Script:

<#
 Install Wrapper 1.0
 Author: Mikael Nystrom
 http://www.deploymentbunny.com 
#>
param($Username,$Password,$mode)
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"}
        }
    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.log"
    }
    }
}
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"

$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList "$env:COMPUTERNAM\$UserName", ($Password | ConvertTo-SecureString -AsPlainText -Force)
$Con = Connect-HPBIOS -IP $env:COMPUTERNAME -Credential $Credentials -ErrorAction Stop

Write-Output "$ScriptName -  Selected Mode: $Mode"

if($mode -eq "FullPower"){
    Set-HPBIOSPowerProfile -Profile Maximum_Performance -Connection $Con
    Set-HPBIOSPowerRegulator -Regulator Static_High_Performance -Connection $Con
    Write-Output "$ScriptName - HP PowerProfile is set to $((Get-HPBIOSPowerProfile -Connection $Con).HPPowerProfile)"
    Write-Output "$ScriptName - HP PowerRegulator is set to $((Get-HPBIOSPowerRegulator -Connection $Con).HPPowerRegulator)"
}

if($mode -eq "TreeHugging"){
    Set-HPBIOSPowerProfile -Profile Minimum_Power -Connection $Con
    Set-HPBIOSPowerRegulator -Regulator Dynamic_Power_Savings -Connection $Con
    Write-Output "$ScriptName - HP PowerProfile is set to $((Get-HPBIOSPowerProfile -Connection $Con).HPPowerProfile)"
    Write-Output "$ScriptName - HP PowerRegulator is set to $((Get-HPBIOSPowerRegulator -Connection $Con).HPPowerRegulator)"
}

. Stop-Logging

Using the script from the command prompt:

Execute the following from an elevated Command Prompt

PowerShell.exe -ExecutionPolicy ByPass -File Configure-HPBIOS.ps1 -Mode FullPower -UserName Administrator –Password P@ssw0rd

Using the script from the PowerShell prompt:

Execute the following from an elevated PowerShell Prompt

.\Configure-HPBIOS.ps1 -Mode FullPower -UserName Administrator –Password P@ssw0rd

Using the script in a Task Sequence when you deploy the server:

You can run the script as PowerShell script in the Task Sequence, or run it as an Application. I prefer to use it as an application since it then can be controlled using rules.

The Config-HPBios application:

image
Here you can see the Quiet install command in the application.

Quiet install command: PowerShell.exe -ExecutionPolicy ByPass -File Configure-HPBIOS.ps1 -Mode %HPPowerMode% -UserName Administrator -Password %AdminPassword%

This command will execute PowerShell and feed the script with Property HPPowerMode (that needs to be FullPower or TreeHugging). This property can be set in CustomSettings.ini or as step in the Task Sequence.

image
Here you can see the Set Task Sequence Variable HPPowerMode set to FullPower.

The actually configuration will be done during the Install step, since it is an application in my case. but it is possible to run the app directly after the Variable has been set.

Check the log file for the result:

image
The log file shows the settings.

/mike

Posted in HP, OS Deployment, OSD, PowerShell | Tagged: , , , , | 1 Comment »

Working in the Datacenter – Application Wrapper for HP BIOS CmdLets – Deploy it during OSD

Posted by Mikael Nystrom on March 7, 2016

In a previous blogpost a shortly described what you can do with the “HP BIOS CmdLets for Windows PowerShell (x64)” and in this post I’ll give you a PowerShell wrapper for LTI/ZTI to deploy it.

Download from installer from

http://h20566.www2.hpe.com/hpsc/swd/public/detail?sp4ts.oid=5440658&swItemId=MTX_1cedc5b3a4ec4bc7a942f6e682&swEnvOid=4168

image

The LTI/ZTI Wrapper:

It is very simple, basically create a folder called “Install – HPBIOSCmdlets”, in the folder, create a folder called “Source” and in that folder you save the MSI file from HP (the download is a EXE, just unzip it and it will be a MSI file inside) and then you save the PowerShell installer in the “Install – HPBIOSCmdlets” folder, like this

image

Here is the:

<#
 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"}
        }
    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.txt"

    }
    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"

$Executable = "msiexec.exe"
$Arguments = "/i ""$SOURCEROOT\HPBIOSCmdlets-x64.msi"" /qb"

Write-Output "$ScriptName - Executable: $Executable"
Write-Output "$ScriptName - Arguments: $Arguments"

Invoke-Exe -Executable $Executable -Arguments $Arguments -Verbose

. Stop-Logging

Create the Application in the Task Sequence:

(This how it is done in LiteTouch, but it will be the same in ConfigMgr)

Create a new Application, browse to the folder you created and use this as your command line:

PowerShell.exe -ExecutionPolicy Bypass -File Install-HPBIOSCmdlets-x64.ps1

image
It should look something like this.

The logfile

It will end up in C:\Windows\Temp\Deploymentlogs (for LTI) and should look something like this:

image

/mike

Posted in BIOS, HP, OS Deployment, OSD, PowerShell | Tagged: , , , , , | 2 Comments »