2015-11-02 23:27:46 +00:00
|
|
|
import-module dism -verbose:$false
|
|
|
|
|
2015-11-11 21:50:37 +00:00
|
|
|
$OfficeVersionId = @{
|
|
|
|
o2013 = "o2013"
|
|
|
|
}
|
|
|
|
$IsoUrls = @{
|
|
|
|
$WindowsVersionId.w81 = @{
|
|
|
|
$ArchitectureId.i386 = "http://care.dlservice.microsoft.com/dl/download/B/9/9/B999286E-0A47-406D-8B3D-5B5AD7373A4A/9600.17050.WINBLUE_REFRESH.140317-1640_X86FRE_ENTERPRISE_EVAL_EN-US-IR3_CENA_X86FREE_EN-US_DV9.ISO"
|
|
|
|
$ArchitectureId.amd64 = "http://care.dlservice.microsoft.com/dl/download/B/9/9/B999286E-0A47-406D-8B3D-5B5AD7373A4A/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_ENTERPRISE_EVAL_EN-US-IR3_CENA_X64FREE_EN-US_DV9.ISO"
|
|
|
|
}
|
|
|
|
$WindowsVersionId.w10 = @{
|
|
|
|
$ArchitectureId.i386 = "http://care.dlservice.microsoft.com/dl/download/C/3/9/C399EEA8-135D-4207-92C9-6AAB3259F6EF/10240.16384.150709-1700.TH1_CLIENTENTERPRISEEVAL_OEMRET_X86FRE_EN-US.ISO"
|
|
|
|
$ArchitectureId.amd64 = "http://care.dlservice.microsoft.com/dl/download/C/3/9/C399EEA8-135D-4207-92C9-6AAB3259F6EF/10240.16384.150709-1700.TH1_CLIENTENTERPRISEEVAL_OEMRET_X64FRE_EN-US.ISO"
|
|
|
|
}
|
|
|
|
$WindowsVersionId.w10ltsb = @{
|
|
|
|
$ArchitectureId.i386 = "http://care.dlservice.microsoft.com/dl/download/6/2/4/624ECF83-38A6-4D64-8758-FABC099503DC/10240.16384.150709-1700.TH1_CLIENTENTERPRISE_S_EVAL_X86FRE_EN-US.ISO"
|
|
|
|
$ArchitectureId.amd64 = "http://care.dlservice.microsoft.com/dl/download/6/2/4/624ECF83-38A6-4D64-8758-FABC099503DC/10240.16384.150709-1700.TH1_CLIENTENTERPRISE_S_EVAL_X64FRE_EN-US.ISO"
|
|
|
|
}
|
|
|
|
$WindowsVersionId.server2012r2 = @{
|
|
|
|
$ArchitectureId.amd64 = "http://care.dlservice.microsoft.com/dl/download/6/2/A/62A76ABB-9990-4EFC-A4FE-C7D698DAEB96/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_SERVER_EVAL_EN-US-IR3_SSS_X64FREE_EN-US_DV9.ISO"
|
|
|
|
}
|
|
|
|
$OfficeVersionId.o2013 = @{
|
|
|
|
$ArchitectureId.i386 = "http://care.dlservice.microsoft.com/dl/download/2/9/C/29CC45EF-4CDA-4710-9FB3-1489786570A1/OfficeProfessionalPlus_x86_en-us.img"
|
|
|
|
$ArchitectureId.amd64 = "http://care.dlservice.microsoft.com/dl/download/2/9/C/29CC45EF-4CDA-4710-9FB3-1489786570A1/OfficeProfessionalPlus_x64_en-us.img"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-02 23:27:46 +00:00
|
|
|
# TODO: Copy-ItemAndExclude
|
|
|
|
# function Copy-ItemAndExclude {
|
|
|
|
# [cmdletbinding()] param(
|
|
|
|
# [parameter(mandatory=$true)] [string] $path,
|
|
|
|
# [parameter(mandatory=$true)] [string] $destination,
|
|
|
|
# [parameter(mandatory=$true)] [string[]] $exclude,
|
|
|
|
# [switch] $force
|
|
|
|
# )
|
|
|
|
# $path = resolve-path $path | select -expand path
|
|
|
|
# $sourceItems = Get-ChildItem -Path $path -Recurse -Exclude $exclude
|
|
|
|
# Write-EventLogWrapper "Found $($sourceItems.count) items to copy from '$path'"
|
|
|
|
# #$sourceItems | copy-item -force:$force -destination {Join-Path $destination $_.FullName.Substring($path.length)}
|
|
|
|
# $sourceItems | copy-item -force:$force -destination {
|
|
|
|
# if ($_.GetType() -eq [System.IO.FileInfo]) {
|
|
|
|
# Join-Path $destination $_.FullName.Substring($path.length)
|
|
|
|
# }
|
|
|
|
# else {
|
|
|
|
# Join-Path $destination $_.Parent.FullName.Substring($path.length)
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
.description
|
|
|
|
Get the path of the Windows ADK or AIK or whatever the fuck they're calling it from a format string
|
|
|
|
- {0} is always the WAIK directory
|
|
|
|
- e.g. "C:\Program Files (x86)\Windows Kits\8.1\"
|
|
|
|
- e.g. "X:\Program Files\Windows Kits\8.0"
|
|
|
|
- {1} is always the host architecture (x86 or amd64)
|
|
|
|
- i THINK this is right, but I don't understand WHY. why do you need an amd64 version of oscdimg.exe?
|
|
|
|
- however, there are arm executables lying around, and i definitely can't execute those. wtf?
|
|
|
|
|
|
|
|
So we expect a string like "{0}\bin\{1}\wsutil.exe"
|
|
|
|
#>
|
|
|
|
function Get-AdkPath {
|
|
|
|
[cmdletbinding()] param(
|
|
|
|
[parameter(mandatory=$true)] [string] $pathFormatString
|
|
|
|
)
|
|
|
|
|
|
|
|
$adkPath = ""
|
|
|
|
$possibleAdkPaths = @("${env:ProgramFiles(x86)}\Windows Kits\8.1","${env:ProgramFiles}\Windows Kits\8.1")
|
|
|
|
$possibleAdkPaths |% { if (test-path $_) { $adkPath = $_ } }
|
|
|
|
if (-not $adkPath) { throw "Could not find the Windows Automated Installation Kit" }
|
|
|
|
Write-EventLogWrapper "Found the WAIK at '$adkPath'"
|
|
|
|
|
|
|
|
$arch = Get-OSArchitecture
|
|
|
|
switch ($arch) {
|
|
|
|
$ArchitectureId.i386 {
|
|
|
|
$formatted = $pathFormatString -f $adkPath,$waikArch
|
|
|
|
if (test-path $formatted) { return $formatted }
|
|
|
|
}
|
|
|
|
$ArchitectureId.amd64 {
|
|
|
|
foreach ($waikArch in @("amd64","x64")) {
|
|
|
|
$formatted = $pathFormatString -f $adkPath,$waikArch
|
|
|
|
if (test-path $formatted) { return $formatted }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default {
|
|
|
|
throw "Could not determine architecture of '$arch'"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw "Could not resolve format string '$pathFormatString' to an existing path"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function New-WindowsInstallMedia { # TODO fixme not sure I wanna handle temp dirs this way??
|
|
|
|
[cmdletbinding()] param(
|
|
|
|
[parameter(mandatory=$true)] [string] $sourceIsoPath,
|
|
|
|
[parameter(mandatory=$true)] [string] $installMediaTemp, # WILL BE DELETED
|
|
|
|
[parameter(mandatory=$true)] [string] $installWimPath, # your new install.wim file
|
|
|
|
[parameter(mandatory=$true)] [string] $outputIsoPath
|
|
|
|
)
|
|
|
|
$oscdImgPath = Get-AdkPath "{0}\Assessment and Deployment Kit\Deployment Tools\{1}\Oscdimg\oscdimg.exe"
|
|
|
|
$installWimPath = resolve-path $installWimPath | select -expand path
|
|
|
|
$installMediaTemp = mkdir -force $installMediaTemp | select -expand fullname
|
|
|
|
|
|
|
|
$outputIsoParentPath = split-path $outputIsoPath -parent
|
|
|
|
$outputIsoFilename = split-path $outputIsoPath -leaf
|
|
|
|
$outputIsoParentPath = mkdir -force $outputIsoParentPath | select -expand fullname
|
|
|
|
|
|
|
|
if (test-path $installMediaTemp) { rm -recurse -force $installMediaTemp }
|
|
|
|
mkdir -force $installMediaTemp | out-null
|
|
|
|
|
|
|
|
$diskVol = get-diskimage -imagepath $sourceIsoPath | get-volume
|
|
|
|
if (-not $diskVol) {
|
|
|
|
mount-diskimage -imagepath $sourceIsoPath
|
|
|
|
$diskVol = get-diskimage -imagepath $sourceIsoPath | get-volume
|
|
|
|
}
|
|
|
|
$driveLetter = $diskVol | select -expand DriveLetter
|
|
|
|
$existingInstallMediaDir = "${driveLetter}:"
|
|
|
|
|
|
|
|
# TODO: the first copy here copies the original install.wim, and the second copies the new one over it
|
|
|
|
# this is really fucking dumb right? but then, THIS is way fucking dumber:
|
|
|
|
# http://stackoverflow.com/questions/731752/exclude-list-in-powershell-copy-item-does-not-appear-to-be-working
|
|
|
|
# PS none of those solutions are generic enough to get included so fuck it
|
|
|
|
copy-item -recurse -path "$existingInstallMediaDir\*" -destination "$installMediaTemp" -verbose:$verbose
|
|
|
|
remove-item -force -path "$installMediaTemp\sources\install.wim"
|
|
|
|
copy-item -path $installWimPath -destination "$installMediaTemp\sources\install.wim" -force -verbose:$verbose
|
|
|
|
|
|
|
|
$etfsBoot = resolve-path "$existingInstallMediaDir\boot\etfsboot.com" | select -expand Path
|
|
|
|
$oscdimgCall = '& "{0}" -m -n -b"{1}" "{2}" "{3}"' -f @($oscdImgPath, $etfsBoot, $installMediaTemp, $outputIsoPath)
|
|
|
|
Write-EventLogWrapper "Calling OSCDIMG: '$oscdimgCall"
|
|
|
|
Invoke-ExpressionAndCheck $oscdimgCall -verbose:$verbose
|
|
|
|
|
|
|
|
dismount-diskimage -imagepath $sourceIsoPath
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
<#
|
|
|
|
.notes
|
|
|
|
The install.wim file doesn't (ever? sometimes?) denote architecture in its image names, but boot.wim (always? usually?) does
|
|
|
|
#>
|
|
|
|
function Get-BootWimArchitecture {
|
|
|
|
[cmdletbinding()] param(
|
|
|
|
[parameter(mandatory=$true)] $wimFile
|
|
|
|
)
|
|
|
|
$bootWimInfo = Get-WindowsImage -imagePath $wimFile -verbose:$verbose
|
|
|
|
|
|
|
|
$arch = $null
|
|
|
|
if (-not $bootWimInfo) { throw "Got no information for wimfile at '$wimFile'"}
|
|
|
|
elseif ($bootWimInfo[0].ImageName -match "x86") { $arch = $ArchitectureId.i386 }
|
|
|
|
elseif ($bootWimInfo[0].ImageName -match "x64") { $arch = $ArchitectureId.amd64 }
|
|
|
|
else { throw "Could not determine architecture for '$wimFile'"}
|
|
|
|
|
|
|
|
write-verbose "Found an architecture of '$arch' for '$wimFile'"
|
|
|
|
return $arch
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function Apply-WindowsUpdatesToIso {
|
|
|
|
[cmdletbinding()] param (
|
|
|
|
[parameter(mandatory=$true)] [string] $inputIso,
|
|
|
|
[parameter(mandatory=$true)] [string] $outputIso,
|
|
|
|
[parameter(mandatory=$true)] [string] $wsusOfflineDir,
|
|
|
|
[parameter(mandatory=$true)] [string] $wimMountDir
|
|
|
|
)
|
|
|
|
|
|
|
|
$myWimMounts = @()
|
|
|
|
|
|
|
|
mount-diskimage -imagepath $inputIso
|
|
|
|
$mountedDrive = get-diskimage -imagepath $inputIso | get-volume | select -expand DriveLetter
|
|
|
|
|
|
|
|
$installWim = "$labTempDir\install.wim"
|
|
|
|
if (-not (test-path $installWim)) {
|
|
|
|
cp "${mountedDrive}:\Sources\install.wim" $labTempDir -verbose:$verbose
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write-verbose "Using EXISTING install.wim at '$installWim'"
|
|
|
|
}
|
|
|
|
Set-ItemProperty -path $installWim -name IsReadOnly -value $false -force
|
|
|
|
|
|
|
|
$arch = Get-BootWimArchitecture -wimFile "${mountedDrive}:\sources\boot.wim" -verbose:$verbose
|
|
|
|
dismount-diskimage -imagepath $inputIso
|
|
|
|
|
|
|
|
$wimInfo = Get-WindowsImage -imagePath $installWim
|
|
|
|
$shortCode = Get-WOShortCode -OSName $wimInfo[0].ImageName -OSArchitecture $arch
|
|
|
|
#$updatePath = resolve-path "${wsusOfflineDir}\client\$shortCode\glb" | select -expand Path
|
|
|
|
$updatePath = "D:\iso\wintriallab\temp-slipstream\WSUSCache\w63-i386-glb"
|
|
|
|
|
|
|
|
foreach ($wimInfo in (Get-WindowsImage -imagePath $installWim)) {
|
|
|
|
$wimMountSubdir = mkdir "${wimMountDir}\$($wimInfo.ImageIndex)" -force | select -expand fullname
|
|
|
|
Mount-WindowsImage -imagePath $installWim -index $wimInfo.ImageIndex -path $wimMountSubdir
|
|
|
|
|
|
|
|
write-verbose "Applying '$((ls $updatePath).count)' updates to '$wimInfo'''"
|
|
|
|
try {
|
|
|
|
Add-WindowsPackage -PackagePath $updatePath -path $wimMountSubdir
|
|
|
|
}
|
|
|
|
catch {
|
|
|
|
write-verbose "Caught error(s) when installing packages:`n`n$_`n"
|
|
|
|
}
|
|
|
|
|
|
|
|
Dismount-WindowsImage -Path $wimMountSubdir -Save
|
|
|
|
}
|
|
|
|
|
|
|
|
New-WindowsInstallMedia -sourceIsoPath $inputIso -installMediaTemp $installMediaTemp -installWimPath $installWim -outputIsoPath $outputIso
|
|
|
|
}
|