The Deployment Bunny

OS Deployment, Virtualization, Microsoft based Infrastructure…

  • Archives

  • Meta

PowerShell Is King – Deploying Windows To Go devices using PowerShell

Posted by Mikael Nystrom on December 22, 2013

The basic idea is simple, just apply the wim file to the USB and you are done, or let the user run the utility on their own, or maybe, let the user execute the app in SCCM. All of these methods works ok, but it could be done better and/or more flexible. I have seen and used some of these solutions in SCCM, but some times you would like to treat the Windows to Go devices as a computer. Things like controlling naming, OU location, make sure they have the correct drivers and patches, what GPO’s they should have, make sure the device is correctly joined in the domain and more. In line of business Self Service is very nice and handy but it does not always work, it “depends”.

Before you begin.

There is a couple of details you should know about.

  • Windows to go is a Windows Enterprise Feature, so it works with Windows 8 Enterprise edition and Windows 8.1 Enterprise edition
  • It does require a USB device that act as a hard drive, NOT a thumb drive, it needs to be a disk  http://technet.microsoft.com/en-us/library/hh831833.aspx#wtg_hardware
  • It needs to be activated, you should consider KMS or Active Directory integrated activation. MAK is NOT supported
  • The idea is to have a trusted OS in any device so that you can access job related information, i strongly recommend Direct Access as a method.
  • You do not need every driver, but you do need network drivers and maybe graphic drivers in the image, focus NOT on make/model rather generic OEM drivers or from Microsoft Update Catalog http://catalog.update.microsoft.com/v7/site/home.aspx
  • I did a session on MMS on the subject, so if you have the time you can watch it here – http://channel9.msdn.com/Events/MMS/2013/DC-B317

What does the script do?

It will find a device that is suitable, partition and format it, apply the wim file, inject drivers if you need, inject patches if you need, create a computer name, join it into the domain, enable the local administrator account (nice for support), it can also randomize the computer name and password and it will save all that information in a text file. It is very easy to change the script into whatever you need it to do.

NOTE: If you want to be 100% sure it picks the correct disk, run the following command in an elevated PowerShell prompt:

Get-Disk | Where-Object {$_.Path -match “USBSTOR” -and $_.Size -gt 20Gb -and -not $_.IsBoot}

As long as you see the correct disk, you are fine. If you don’t, you need to modify the criteria OR remove the other drives.

Data input

The script uses a standard Param section that will collect things like Wim location, domain name, index in wim, name of computer, the possibility to generate the local admin password and generate the computer name based on a prefix

image

Functions

  • Create the unattend.xml file, generate the random computer name, generate the local admin password, patch the image and dump the data in a text file.
    • CreateUnattendFile will create the unattendfile, it does contain logic for both 32 and 64 bit windows and the file is used twice, the first time when applying the file to set the SAN-Policy and the second time to configure the computer when it boots.
    • CreateRandomComputername is the randomizer for naming.
    • CreateRandomLocalAdminPassword is a function I write a while back, it is based on various posts, TechNet and then some. It is configurable in the way that you can decide what characters that should be included, length and strength and since it is a function it is easy to steel and put in any other script.
    • PatchTheImage is basically a foreach loop that traverse the folder with  patches and apply them one-by-one
    • DocData is a function that create a PSObject of all data so it is easy to dump it in a form you need, you could easily dump the data directly into a database or something with little work

image

The static values

There are some static values in the script

image

Fixing the disk

In this part we will find the disk, clean it, partition and format it, find the drive letters and fix so it does not gets a drive letter automatically assigned in a computer.

image

Adding Windows

In this part we will apply Windows using Expand-Windows Image, apply the unattended file offline section to the image, copy the unattend.xml to the drive, do an Offline Domain Join and apply that to the image

image

Finish up

Now it is time to add patches and drivers to it.

image

Running the script

Make sure you execute the script from an elevated PowerShell prompt on a Windows 8.1 or Windows Server 2012 R2

Example 1: Assign the name and password using the randomizer

.\Create-WTGDevice.ps1 -WIMFile ‘D:\WTGDemo\Windows 8.1 Enterprise x64 RTM\sources\install.wim’ -DomainName network.local -Index 1

Example 2: Assign the name and password static

.\Create-WTGDevice.ps1 -WIMFile ‘D:\WTGDemo\Windows 8.1 Enterprise x64 RTM\sources\install.wim’ -DomainName network.local -Index 1 -RandomComputerName $false -RandomLocalAdminPassword $false

Result of running the script

image

Download the script from here http://sdrv.ms/1hwUlsW

/mike

The Script as plain text


<#
Created:     2013-12-22
Version:     1.0
Author       Mikael Nystrom

Disclaimer:
This script is provided “AS IS” with no warranties, confers no rights and
is not supported by the author.

Author – Mikael Nystrom
Twitter: @mikael_nystrom
Blog   : http://deploymentbunny.com
#>

param (
[parameter(Mandatory=$false)]
[string]
#Path to wim.
$WIMFile = “D:\WTGDemo\Windows 8.1 Enterprise x64 RTM\sources\install.wim”,

[parameter(Mandatory=$false)]
[string]
#Domain to which to join the Windows To Go workspaces.
$DomainName = “network.local”,

[parameter(Mandatory=$false)]
[string]
#WIM file Index to use.
$Index = “1”,

[parameter(Mandatory=$false)]
[string]
$Computername,

[parameter(Mandatory=$false)]
[string]
$RandomComputerName = $true,

[parameter(Mandatory=$false)]
[string]
$RandomLocalAdminPassword = $true
)

Function CreateUnattendFile{
if(Test-Path “WtgUnattend.xml”){del .\WtgUnattend.xml}
$unattendFile = New-Item “WtgUnattend.xml” -type File
set-Content $unattendFile ‘<?xml version=”1.0″ encoding=”utf-8″?>’
add-content $unattendFile ‘<unattend xmlns=”urn:schemas-microsoft-com:unattend”>’
add-content $unattendFile ‘    <settings pass=”oobeSystem”>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Shell-Setup” publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” processorArchitecture=”AMD64″ xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <OOBE>’
add-content $unattendFile ‘                <HideEULAPage>true</HideEULAPage>’
add-content $unattendFile ‘                <ProtectYourPC>1</ProtectYourPC>’
add-content $unattendFile ‘                <NetworkLocation>Work</NetworkLocation>’
add-content $unattendFile ‘                <HideLocalAccountScreen>true</HideLocalAccountScreen>’
add-content $unattendFile ‘                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>’
add-content $unattendFile ‘                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>’
add-content $unattendFile ‘                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>’
add-content $unattendFile ‘            </OOBE>’
add-content $unattendFile ”            <RegisteredOwner>$OrgName</RegisteredOwner>”
add-content $unattendFile ”            <TimeZone>$TimeZoneName</TimeZone>”
add-content $unattendFile ”            <RegisteredOrganization>$OrgName</RegisteredOrganization>”
add-Content $unattendFile ‘            <UserAccounts>’
add-Content $unattendFile ‘                <AdministratorPassword>’
add-Content $unattendFile ”                    <Value>$LocalAdminPassword</Value>”
add-Content $unattendFile ‘                    <PlainText>True</PlainText>’
add-Content $unattendFile ‘                </AdministratorPassword>’
add-Content $unattendFile ‘            </UserAccounts>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-International-Core” publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” processorArchitecture=”AMD64″>’
add-content $unattendFile ”          <InputLocale>$InputLocale</InputLocale>”
add-content $unattendFile ”          <SystemLocale>$SystemLocale</SystemLocale>”
add-content $unattendFile ”          <UILanguage>$UILanguage</UILanguage>”
add-content $unattendFile ”          <UserLocale>$UserLocale</UserLocale>”
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-WinRE-RecoveryAgent” processorArchitecture=”amd64″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <UninstallWindowsRE>true</UninstallWindowsRE>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Shell-Setup” publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” processorArchitecture=”X86″ xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <OOBE>’
add-content $unattendFile ‘                <HideEULAPage>true</HideEULAPage>’
add-content $unattendFile ‘                <ProtectYourPC>1</ProtectYourPC>’
add-content $unattendFile ‘                <NetworkLocation>Work</NetworkLocation>’
add-content $unattendFile ‘                <HideLocalAccountScreen>true</HideLocalAccountScreen>’
add-content $unattendFile ‘                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>’
add-content $unattendFile ‘                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>’
add-content $unattendFile ‘                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>’
add-content $unattendFile ‘            </OOBE>’
add-content $unattendFile ”            <RegisteredOwner>$OrgName</RegisteredOwner>”
add-content $unattendFile ”            <TimeZone>$TimeZoneName</TimeZone>”
add-content $unattendFile ”            <RegisteredOrganization>$OrgName</RegisteredOrganization>”
add-Content $unattendFile ‘            <UserAccounts>’
add-Content $unattendFile ‘                <AdministratorPassword>’
add-Content $unattendFile ”                    <Value>$LocalAdminPassword</Value>”
add-Content $unattendFile ‘                    <PlainText>True</PlainText>’
add-Content $unattendFile ‘                </AdministratorPassword>’
add-Content $unattendFile ‘            </UserAccounts>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-International-Core” publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” processorArchitecture=”x86″>’
add-content $unattendFile ”          <InputLocale>$InputLocale</InputLocale>”
add-content $unattendFile ”          <SystemLocale>$SystemLocale</SystemLocale>”
add-content $unattendFile ”          <UILanguage>$UILanguage</UILanguage>”
add-content $unattendFile ”          <UserLocale>$UserLocale</UserLocale>”
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-WinRE-RecoveryAgent” processorArchitecture=”x86″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <UninstallWindowsRE>true</UninstallWindowsRE>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘    </settings>’
add-content $unattendFile ‘    <settings pass=”specialize”>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Shell-Setup” processorArchitecture=”amd64″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ”         <ComputerName>$computername</ComputerName>”
add-content $unattendFile ‘         <CopyProfile>true</CopyProfile>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Deployment” processorArchitecture=”amd64″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘         <RunSynchronous>’
add-content $unattendFile ‘          <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>EnableAdmin</Description>’
add-content $unattendFile ‘           <Order>1</Order>’
add-content $unattendFile ‘           <Path>cmd /c net user Administrator /active:yes</Path>’
add-content $unattendFile ‘          </RunSynchronousCommand>’
add-content $unattendFile ‘          <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>UnfilterAdministratorToken</Description>’
add-content $unattendFile ‘           <Order>2</Order>’
add-content $unattendFile ‘           <Path>cmd /c reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v FilterAdministratorToken /t REG_DWORD /d 0 /f</Path>’
add-content $unattendFile ‘          </RunSynchronousCommand>’
add-content $unattendFile ‘          <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>disable user account page</Description>’
add-content $unattendFile ‘           <Order>3</Order>’
add-content $unattendFile ‘           <Path>reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\OOBE /v UnattendCreatedUser /t REG_DWORD /d 1 /f</Path>’
add-content $unattendFile ‘          </RunSynchronousCommand>’
add-content $unattendFile ‘         </RunSynchronous>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Shell-Setup” processorArchitecture=”x86″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ”         <ComputerName>$computername</ComputerName>”
add-content $unattendFile ‘         <CopyProfile>true</CopyProfile>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component name=”Microsoft-Windows-Deployment” processorArchitecture=”x86″ publicKeyToken=”31bf3856ad364e35″ language=”neutral” versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘         <RunSynchronous>’
add-content $unattendFile ‘          <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>EnableAdmin</Description>’
add-content $unattendFile ‘           <Order>1</Order>’
add-content $unattendFile ‘           <Path>cmd /c net user Administrator /active:yes</Path>’
add-content $unattendFile ‘         </RunSynchronousCommand>’
add-content $unattendFile ‘         <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>UnfilterAdministratorToken</Description>’
add-content $unattendFile ‘           <Order>2</Order>’
add-content $unattendFile ‘           <Path>cmd /c reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v FilterAdministratorToken /t REG_DWORD /d 0 /f</Path>’
add-content $unattendFile ‘         </RunSynchronousCommand>’
add-content $unattendFile ‘         <RunSynchronousCommand wcm:action=”add”>’
add-content $unattendFile ‘           <Description>disable user account page</Description>’
add-content $unattendFile ‘           <Order>3</Order>’
add-content $unattendFile ‘           <Path>reg add HKLM\Software\Microsoft\Windows\CurrentVersion\Setup\OOBE /v UnattendCreatedUser /t REG_DWORD /d 1 /f</Path>’
add-content $unattendFile ‘          </RunSynchronousCommand>’
add-content $unattendFile ‘         </RunSynchronous>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘    </settings>’

add-content $unattendFile ‘    <settings pass=”offlineServicing”>’
add-content $unattendFile ‘        <component language=”neutral” name=”Microsoft-Windows-PartitionManager” processorArchitecture=”amd64″ publicKeyToken=”31bf3856ad364e35″ versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <SanPolicy>4</SanPolicy>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘        <component language=”neutral” name=”Microsoft-Windows-PartitionManager” processorArchitecture=”x86″ publicKeyToken=”31bf3856ad364e35″ versionScope=”nonSxS” xmlns:wcm=”http://schemas.microsoft.com/WMIConfig/2002/State” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>’
add-content $unattendFile ‘            <SanPolicy>4</SanPolicy>’
add-content $unattendFile ‘        </component>’
add-content $unattendFile ‘    </settings>’
add-content $unattendFile ‘</unattend>’

#return the file object
$unattendFile
}
Function CreateRandomComputerName{
#using get-random, we will create a random computer name for the drive.
$suffix = Get-Random
$computername = $RandomComputerNamePrefix + $suffix
}
Function CreateRandomLocalAdminPassword{
param([int]$PasswordLength,[boolean]$Complex)

#Characters to use based
$strSimple = “A”,”B”,”C”,”D”,”E”,”F”,”G”,”H”,”I”,”J”,”K”,”L”,”M”,”N”,”O”,”P”,”Q”,”R”,”S”,”T”,”U”,”V”,”W”,”X”,”Y”,”Z”,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”0″,”a”,”b”,”c”,”d”,”e”,”f”,”g”,”h”,”i”,”j”,”k”,”l”,”m”,”n”,”o”,”p”,”q”,”r”,”s”,”t”,”u”,”v”,”w”,”x”,”y”,”z”
$strComplex = “A”,”B”,”C”,”D”,”E”,”F”,”G”,”H”,”I”,”J”,”K”,”L”,”M”,”N”,”O”,”P”,”Q”,”R”,”S”,”T”,”U”,”V”,”W”,”X”,”Y”,”Z”,”1″,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”0″,”a”,”b”,”c”,”d”,”e”,”f”,”g”,”h”,”i”,”j”,”k”,”l”,”m”,”n”,”o”,”p”,”q”,”r”,”s”,”t”,”u”,”v”,”w”,”x”,”y”,”z”,”!”,”_”
$strNumbers = “1”,”2″,”3″,”4″,”5″,”6″,”7″,”8″,”9″,”0″

#Check to see if password contains at least 1 digit
$bolHasNumber = $false
$pass = $null

#Sets which Character Array to use based on $Complex
if ($Complex){$strCharacters = $strComplex}else{$strCharacters = $strSimple}

#Loop to actually generate the password
for ($i=0;$i -lt $PasswordLength; $i++){$c = get-random -InputObject $strCharacters
if ([char]::IsDigit($c)){$bolHasNumber = $true}$pass += $c}

#Check to see if a Digit was seen, if not, fixit
if ($bolHasNumber){return $pass}else{
$pos = Get-Random -Maximum $PasswordLength
$n = get-random -InputObject $strNumbers
$pwArray = $pass.ToCharArray()
$pwArray[$pos] = $n
$pass = “”
foreach ($s in $pwArray){$pass += $s}
return $pass
}}
Function PatchTheImage{
$AllPatches = Get-ChildItem -Path $PatchFolder -Filter *.msu -Recurse
foreach ($patch in $AllPatches)
{
$PatchFullName =  $patch.FullName
$PatchFullName
Add-WindowsPackage -PackagePath $PatchFullName -Path $OSDriveLetter`: -Verbose
}
}
Function DocData {
New-Object PSObject -Property @{
Computername = $($computername);
OU =  $($OUPath);
TimeZoneName = $($TimeZoneName);
LocalAdminPassword = $($LocalAdminPassword);
InputLocale = $($InputLocale);
SystemLocale = $($SystemLocale);
UserLocale = $($UserLocale);
UILanguage = $($UILanguage);
OrgName = $($OrgName);
WIMFile = $($WIMFile);
DomainName = $($DomainName);
}
}

if(Test-Path $WIMFile ){write-output “Image: $WIMFile”}else{write-output “Unable to find image: $WIMFile” “Exiting the script”|exit}

#Setting Var
$InputLocale = “sv-se”
$SystemLocale = “sv-se”
$UserLocale = “sv-se”
$UILanguage = “sv-se”
$OrgName = “ViaMonstra”
$Index = “1”
$OUPath = “OU=WTG,OU=Computers,OU=Network,DC=network,DC=local”
$GPO = “DirectAccess Client Settings”
$TimeZoneName = “W. Europe Standard Time”
$LocalAdminPassword = “P@ssw0rd”
$DriverFolder = “D:\WTGDemo\Drivers”
$PatchFolder = “D:\WTGDemo\Patches”
$RandomComputerNamePrefix = “WTG-“
$RunningFromFolder = $MyInvocation.MyCommand.Path | Split-Path -Parent

if($RandomComputerName -like $True){. CreateRandomComputerName}else{}
if($RandomLocalAdminPassword -like $True){$LocalAdminPassword = CreateRandomLocalAdminPassword -PasswordLength 10 -Complex $true}else{}

#Write out info
Write-Output “InputLocale: $InputLocale”
Write-Output “SystemLocale: $SystemLocale”
Write-Output “UserLocale: $UserLocale”
Write-Output “UserLocale: $UILanguage”
Write-Output “Index: $Index”
Write-Output “OUPath $OUPath”
Write-Output “GPO: $GPO”
Write-Output “TimeZoneName: $TimeZoneName”
Write-Output “LocalAdminPassword: $LocalAdminPassword”
Write-Output “DriverFolder: $DriverFolder”
Write-Output “Computername: $computername”
Write-Output “LocalAdminPassword: $LocalAdminPassword”
Write-Output “RunningFromFolder: $RunningFromFolder”

#Create helper files
Write-Output “Creating unattend.xml”
$unattendFile = . CreateUnattendFile

# The following command will set $Disk to all USB drives with >20 GB of storage
Write-Output “Looking for a target”
$Disk = Get-Disk | Where-Object {$_.Path -match “USBSTOR” -and $_.Size -gt 20Gb -and -not $_.IsBoot}
Write-Output “Target found: “$Disk
Clear-Disk –InputObject $Disk[0] -RemoveData –confirm:$False -ErrorAction Stop
Initialize-Disk –InputObject $Disk[0] -PartitionStyle MBR -ErrorAction Stop
$SystemPartition = New-Partition –InputObject $Disk[0] -Size (350MB) -IsActive -ErrorAction Stop
Format-Volume -NewFileSystemLabel “UFD-System” -FileSystem FAT32 -Partition $SystemPartition –Confirm:$False -ErrorAction Stop
$OSPartition = New-Partition –InputObject $Disk[0] -UseMaximumSize -ErrorAction Stop
Format-Volume -NewFileSystemLabel “UFD-Windows” -FileSystem NTFS -Partition $OSPartition –Confirm:$False -ErrorAction Stop
Add-PartitionAccessPath -DiskNumber $Disk.Number -PartitionNumber 1 -AssignDriveLetter -ErrorAction Stop
Add-PartitionAccessPath -DiskNumber $Disk.Number -PartitionNumber 2 -AssignDriveLetter -ErrorAction Stop
$SystemDriveLetter = Get-Volume -FileSystemLabel UFD-System -ErrorAction Stop
$OSDriveLetter = Get-Volume -FileSystemLabel UFD-Windows -ErrorAction Stop

$SystemDriveLetter = [string]$SystemDriveLetter.DriveLetter
$OSDriveLetter = [string]$OSDriveLetter.DriveLetter

Write-Output “SystemDriveLetter is now $SystemDriveLetter” -Verbose
Write-Output “OSDriveLetter is now $OSDriveLetter” -Verbose

Write-Output “Setting disk to no default driverletter.”
Set-Partition -InputObject $OSPartition -NoDefaultDriveLetter $TRUE -Verbose

Write-Output “Applying image using Expand-WindowsImage.”
Try{Expand-WindowsImage -ImagePath “$WIMFile” -Index $Index -ApplyPath $OSDriveLetter`:\ -Verbose -ErrorAction Stop
}Catch{$ErrorMessage = $_.Exception.Message}

write-output “Applying boot files using BCDBOOT.exe.”
cmd /c “$OSDriveLetter`:\Windows\system32\bcdboot $OSDriveLetter`:\Windows /f ALL /s $SystemDriveLetter`:”
if (!$?){write-output “BCDBOOT.exe failed, exiting script.”
exit
}

write-output “Applying unattend.xml using Use-WindowsUnattend.”
Try{Use-WindowsUnattend -Path $OSDriveLetter`:\ -UnattendPath $unattendFile -Verbose -ErrorAction Stop
}Catch{$ErrorMessage = $_.Exception.Message}

write-output “Copying unattendxml to media”
Copy-Item -Path $unattendFile -Destination $OSDriveLetter`:\Windows\System32\sysprep\unattend.xml -Force -Verbose

write-output “Creating an Offline Domain join object using DJOIN.”
djoin.exe /PROVISION /DOMAIN $DomainName /MACHINE $computername /savefile $RunningFromFolder\tempBLOB.bin /machineou “”$OUPath”” /policynames “”$GPO”” /rootcacerts
if (!$?){write-output “DJOIN /provision failed, exiting.”
exit
}

write-output “Applying the Offline Object using DJOIN.”
djoin /requestodj /loadfile $RunningFromFolder\tempBLOB.bin /windowspath $OSDriveLetter`:\windows
if (!$?){write-output “DJOIN /requestodj failed, exiting.”
exit
}

#Add Drivers
write-output “Adding drivers using Add-WindowsDriver.”
Add-WindowsDriver -Path $OSDriveLetter`:\ -Driver $DriverFolder -Recurse -Verbose

#Patch it
Write-Output “Patching from $PatchFolder using Add-WindowsPackage”
. PatchTheImage

#Remove blob
write-output “remove blob”
Remove-Item $RunningFromFolder\tempBLOB.bin -Verbose

#Set disk Offline
Set-Disk -Number $disk.Number -IsOffline $true -Verbose

#Export critical information to a text file
. DocData | Out-File -FilePath $RunningFromFolder\$Computername.txt -Force


3 Responses to “PowerShell Is King – Deploying Windows To Go devices using PowerShell”

  1. […] are more ways in doing things, another way is via PowerShell. Have a look at Mikael Nystrom his PowerShell Is King – Deploying Windows To Go devices using PowerShell blog to find out […]

  2. […] are more ways in doing things, another way is via PowerShell. Have a look at Mikael Nystrom his PowerShell Is King – Deploying Windows To Go devices using PowerShell blog to find out […]

  3. […] an alternative, Mikael Nystrom has posted a comprehensive blog post about Deploying Windows To Go devices using PowerShell. He generously published the script as well. Thanks […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 3,866 other followers

%d bloggers like this: