Added functionality to download latest CU, Defender, OneDrive, Edge

This commit is contained in:
rbalsleyMSFT
2024-02-26 18:06:16 -08:00
parent a4cd349f45
commit 0b334ad95e
2 changed files with 391 additions and 13 deletions
+10 -1
View File
@@ -1,6 +1,11 @@
REM Put each app install on a separate line
REM M365 Apps/Office ProPlus
d:\Office\setup.exe /configure d:\Office\DeployFFU.xml
REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml
REM Install Defender Platform Update
REM Install Defender Definitions
REM Install Windows Security Platform Update
REM Install OneDrive Per Machine
REM Install Edge Stable
REM Add additional apps below here
REM Contoso App (Example)
REM msiexec /i d:\Contoso\setup.msi /qn /norestart
@@ -10,4 +15,8 @@ del c:\windows\panther\unattend\unattend.xml /F /Q
del c:\windows\panther\unattend.xml /F /Q
taskkill /IM sysprep.exe
timeout /t 10
REM Run Component Cleanup since dism /online /cleanup-image /analyzecomponentcleanup recommends it
REM If adding latest CU, definitely need to do this to keep FFU size smaller
dism /online /cleanup-image /startcomponentcleanup /resetbase
REM Sysprep/Generalize
c:\windows\system32\sysprep\sysprep.exe /quiet /generalize /oobe
+381 -12
View File
@@ -185,7 +185,9 @@ param(
[ValidateSet(10, 11)]
[int]$WindowsRelease = 11,
[Parameter(Mandatory = $false)]
[ValidateSet('x86', 'x64')]
[string]$WindowsVersion = '23h2',
[Parameter(Mandatory = $false)]
[ValidateSet('x86', 'x64', 'arm64')]
[string]$WindowsArch = 'x64',
[ValidateScript({
$allowedLang = @('ar-sa', 'bg-bg', 'cs-cz', 'da-dk', 'de-de', 'el-gr', 'en-gb', 'en-us', 'es-es', 'es-mx', 'et-ee', 'fi-fi', 'fr-ca', 'fr-fr', 'he-il', 'hr-hr', 'hu-hu',
@@ -211,6 +213,11 @@ param(
})]
[bool]$CopyDrivers,
[bool]$RemoveFFU,
[bool]$UpdateLatestCU,
[bool]$UpdateLatestNet,
[bool]$UpdateLatestDefender,
[bool]$UpdateEdge,
[bool]$UpdateOneDrive,
#Will be used in future release
[bool]$CopyPPKG,
[bool]$CopyUnattend
@@ -248,6 +255,10 @@ if (-not $VMPath) { $VMPath = "$VMLocation\$VMName" }
if (-not $VHDXPath) { $VHDXPath = "$VMPath\$VMName.vhdx" }
if (-not $FFUCaptureLocation) { $FFUCaptureLocation = "$FFUDevelopmentPath\FFU" }
if (-not $LogFile) { $LogFile = "$FFUDevelopmentPath\FFUDevelopment.log" }
if (-not $KBPath) { $KBPath = "$FFUDevelopmentPath\KB" }
if (-not $DefenderPath) { $DefenderPath = "$AppsPath\Defender" }
if (-not $OneDrivePath) { $OneDrivePath = "$AppsPath\OneDrive" }
if (-not $EdgePath) { $EdgePath = "$AppsPath\Edge" }
#FUNCTIONS
function WriteLog($LogText) {
@@ -501,6 +512,117 @@ function Get-Office {
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $content
}
}
function Get-KBLink {
param(
[Parameter(Mandatory)]
[string]$Name
)
$results = Invoke-WebRequest -Uri "http://www.catalog.update.microsoft.com/Search.aspx?q=$Name"
$kbids = $results.InputFields |
Where-Object { $_.type -eq 'Button' -and $_.Value -eq 'Download' } |
Select-Object -ExpandProperty ID
Write-Verbose -Message "$kbids"
if (-not $kbids) {
Write-Warning -Message "No results found for $Name"
return
}
$guids = $results.Links |
Where-Object ID -match '_link' |
Where-Object { $_.OuterHTML -match ( "(?=.*" + ( $Filter -join ")(?=.*" ) + ")" ) } |
ForEach-Object { $_.id.replace('_link', '') } |
Where-Object { $_ -in $kbids }
if (-not $guids) {
Write-Warning -Message "No file found for $Name"
return
}
foreach ($guid in $guids) {
Write-Verbose -Message "Downloading information for $guid"
$post = @{ size = 0; updateID = $guid; uidInfo = $guid } | ConvertTo-Json -Compress
$body = @{ updateIDs = "[$post]" }
$links = Invoke-WebRequest -Uri 'https://www.catalog.update.microsoft.com/DownloadDialog.aspx' -Method Post -Body $body |
Select-Object -ExpandProperty Content |
Select-String -AllMatches -Pattern "http[s]?://[^']*\.microsoft\.com/[^']*|http[s]?://[^']*\.windowsupdate\.com/[^']*" |
Select-Object -Unique
foreach ($link in $links) {
$link.matches.value
#Filter out cab files
# #if ($link -notmatch '\.cab') {
# $link.matches.value
# }
}
}
}
function Get-LatestWindowsKB {
param (
[ValidateSet(10, 11)]
[int]$WindowsRelease
)
# Define the URL of the update history page based on the Windows release
if ($WindowsRelease -eq 11) {
$updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information'
}
else {
$updateHistoryUrl = 'https://learn.microsoft.com/en-us/windows/release-health/release-information'
}
# Use Invoke-WebRequest to fetch the content of the page
$response = Invoke-WebRequest -Uri $updateHistoryUrl
# Use a regular expression to find the KB article number
$kbArticleRegex = 'KB\d+'
$kbArticle = [regex]::Match($response.Content, $kbArticleRegex).Value
return $kbArticle
}
function Save-KB {
[CmdletBinding()]
param(
[string[]]$Name,
[string]$Path
)
if ($WindowsArch -eq 'x64') {
[array]$WindowsArch = @("x64", "amd64")
}
foreach ($kb in $name) {
$links = Get-KBLink -Name $kb
foreach ($link in $links) {
#Check if $WindowsArch is an array
if ($WindowsArch -is [array]) {
#Some file names include either x64 or amd64
if ($link -match $WindowsArch[0] -or $link -match $WindowsArch[1]) {
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
elseif (!($link -match 'x64' -or $link -match 'amd64' -or $link -match 'x86' -or $link -match 'arm64')) {
Write-Host "No architecture found in $link, assume it's for all architectures"
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
}
else {
if ($link -match $WindowsArch) {
Start-BitsTransfer -Source $link -Destination $Path
$fileName = ($link -split '/')[-1]
break
}
}
}
}
return $fileName
}
function New-AppsISO {
#Create Apps ISO file
@@ -515,8 +637,7 @@ function New-AppsISO {
WriteLog 'Cleaning up Office and ODT download'
Remove-Item -Path $OfficeDownloadPath -Recurse -Force
Remove-Item -Path "$ODTPath\setup.exe"
}
}
}
function Get-WimFromISO {
#Mount ISO, get Wim file
@@ -1082,11 +1203,12 @@ function Remove-FFUVM {
WriteLog 'Cleaning up VM'
$certPath = 'Cert:\LocalMachine\Shielded VM Local Certificates\'
$VMName = $FFUVM.Name
$Path = $FFUVM.Path
WriteLog "Removing VM: $VMName"
Remove-VM -Name $VMName -Force
WriteLog 'Removal complete'
WriteLog "Removing $VMPath"
Remove-Item -Path $VMPath -Force -Recurse
WriteLog "Removing $Path"
Remove-Item -Path $Path -Force -Recurse
WriteLog 'Removal complete'
WriteLog "Removing HGSGuardian for $VMName"
Remove-HgsGuardian -Name $VMName -WarningAction SilentlyContinue
@@ -1197,7 +1319,8 @@ Function Get-USBDrive{
WriteLog "Found $USBDrivesCount USB drives"
if ($null -eq $USBDrives) {
WriteLog "No removable USB drive found."
WriteLog "No removable USB drive found. Exiting"
Write-Error "No removable USB drive found. Exiting"
exit 1
}
return $USBDrives, $USBDrivesCount
@@ -1389,6 +1512,38 @@ function Get-FFUEnvironment {
Invoke-Process reg "unload HKLM\FFU"
}
#Remove FFU User and Share
$UserExists = Get-LocalUser -Name $UserName -ErrorAction SilentlyContinue
if ($UserExists) {
WriteLog "Removing FFU User and Share"
Remove-FFUUserShare
WriteLog 'Removal complete'
}
#Clean up $KBPath
If (Test-Path -Path $KBPath) {
WriteLog "Removing $KBPath"
Remove-Item -Path $KBPath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $DefenderPath
If (Test-Path -Path $DefenderPath) {
WriteLog "Removing $DefenderPath"
Remove-Item -Path $DefenderPath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $OneDrivePath
If (Test-Path -Path $OneDrivePath) {
WriteLog "Removing $OneDrivePath"
Remove-Item -Path $OneDrivePath -Recurse -Force
WriteLog 'Removal complete'
}
#Clean up $EdgePath
If (Test-Path -Path $EdgePath) {
WriteLog "Removing $EdgePath"
Remove-Item -Path $EdgePath -Recurse -Force
WriteLog 'Removal complete'
}
Writelog 'Removing dirty.txt file'
Remove-Item -Path "$FFUDevelopmentPath\dirty.txt" -Force
WriteLog "Cleanup complete"
@@ -1399,6 +1554,36 @@ function Remove-FFU{
Remove-Item -Path $FFUCaptureLocation\*.ffu -Force
WriteLog "Removal complete"
}
function Clear-InstallAppsandSysprep {
if ($UpdateLatestDefender) {
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Defender Platform Update"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$CmdContent -notmatch 'd:\\Defender*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
#Remove $DefenderPath
WriteLog "Removing $DefenderPath"
Remove-Item -Path $DefenderPath -Recurse -Force
WriteLog "Removal complete"
}
if ($UpdateOneDrive){
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove OneDrive install"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$CmdContent -notmatch 'd:\\OneDrive*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
#Remove $OneDrivePath
WriteLog "Removing $OneDrivePath"
Remove-Item -Path $OneDrivePath -Recurse -Force
WriteLog "Removal complete"
}
if($UpdateEdge){
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to remove Edge install"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$CmdContent -notmatch 'd:\\Edge*' | Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
#Remove $EdgePath
WriteLog "Removing $EdgePath"
Remove-Item -Path $EdgePath -Recurse -Force
WriteLog "Removal complete"
}
}
###END FUNCTIONS
@@ -1460,7 +1645,9 @@ catch {
#Check if environment is dirty
If(Test-Path -Path "$FFUDevelopmentPath\dirty.txt"){
Get-FFUEnvironment
}
}
WriteLog 'Creating dirty.txt file'
New-Item -Path .\ -Name "dirty.txt" -ItemType "file" | Out-Null
#Create apps ISO for Office and/or 3rd party apps
if ($InstallApps) {
@@ -1476,8 +1663,8 @@ if ($InstallApps) {
if (-not $InstallOffice) {
#Modify InstallAppsandSysprep.cmd to REM out the office install command
$cmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $cmdContent -replace '^(d:\\Office\\setup.exe /configure d:\\office\\DeployFFU.xml)', ("REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml")
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(d:\\Office\\setup.exe /configure d:\\office\\DeployFFU.xml)', ("REM d:\Office\setup.exe /configure d:\office\DeployFFU.xml")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
}
@@ -1486,7 +1673,119 @@ if ($InstallApps) {
Get-Office
WriteLog 'Downloading M365 Apps/Office completed successfully'
}
#Update Latest Defender Platform and Definitions - these can't be serviced into the VHDX, will be saved to AppsPath
if ($UpdateLatestDefender) {
WriteLog "`$UpdateLatestDefender is set to true, checking for latest Defender Platform and Definitions"
$Name = 'Update for Microsoft Defender Antivirus antimalware platform'
#Check if $DefenderPath exists, if not, create it
If (-not (Test-Path -Path $DefenderPath)) {
WriteLog "Creating $DefenderPath"
New-Item -Path $DefenderPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
$KBFilePath = Save-KB -Name $Name -Path $DefenderPath
WriteLog "Latest Defender Platform and Definitions saved to $DefenderPath$KBFilePath"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Defender Update Platform
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Defender Platform Update"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Defender Platform Update)', ("REM Install Defender Platform Update`r`nd:\Defender\$KBFilePath")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
#Get Windows Security platform update
$Name = "Windows Security platform definition updates"
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $DefenderPath"
$KBFilePath = Save-KB -Name $Name -Path $DefenderPath
WriteLog "Latest Security Platform Update saved to $DefenderPath$KBFilePath"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Windows Security Platform Update
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Windows Security Platform Update"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Windows Security Platform Update)', ("REM Install Windows Security Platform Update`r`nd:\Defender\$KBFilePath")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
#Download latest Defender Definitions
WriteLog "Downloading latest Defender Definitions"
# Defender def updates can be found https://www.microsoft.com/en-us/wdsi/defenderupdates
if ($WindowsArch -eq 'x64'){
$DefenderDefURL = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64'
}
if ($WindowsArch -eq 'ARM64'){
$DefenderDefURL = 'https://go.microsoft.com/fwlink/?LinkID=121721&arch=arm'
}
try {
Start-BitsTransfer -Source $DefenderDefURL -Destination "$DefenderPath\mpam-fe.exe"
WriteLog "Defender Definitions downloaded to $DefenderPath\mpam-fe.exe"
}
catch {
Write-Host "Downloading Defender Definitions Failed"
WriteLog "Downloading Defender Definitions Failed with error $_"
throw $_
}
#Modify InstallAppsandSysprep.cmd to add in $DefenderPath on the line after REM Install Defender Definitions
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Defender Definitions"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Defender Definitions)', ("REM Install Defender Definitions`r`nd:\Defender\mpam-fe.exe")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Download and Install OneDrive Per Machine
if($UpdateOneDrive){
#Check if $OneDrivePath exists, if not, create it
If (-not (Test-Path -Path $OneDrivePath)) {
WriteLog "Creating $OneDrivePath"
New-Item -Path $OneDrivePath -ItemType Directory -Force | Out-Null
}
WriteLog "Downloading latest OneDrive client"
$OneDriveURL = 'https://go.microsoft.com/fwlink/?linkid=844652'
try {
Start-BitsTransfer -Source $OneDriveURL -Destination "$OneDrivePath\OneDriveSetup.exe"
WriteLog "Defender Definitions downloaded to $OneDrivePath\OneDriveSetup.exe"
}
catch {
Write-Host "Downloading OneDrive client Failed"
WriteLog "Downloading OneDrive client Failed with error $_"
throw $_
}
#Modify InstallAppsandSysprep.cmd to add in $OneDrivePath on the line after REM Install Defender Definitions
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include OneDrive client"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install OneDrive Per Machine)', ("REM Install OneDrive Per Machine`r`nd:\OneDrive\OneDriveSetup.exe /allusers")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Download and Install Edge Stable
if ($UpdateEdge) {
WriteLog "`$UpdateEdge is set to true, checking for latest Edge Stable $WindowsArch release"
$Name = "microsoft edge stable -extended $WindowsArch"
#Check if $EdgePath exists, if not, create it
If (-not (Test-Path -Path $EdgePath)) {
WriteLog "Creating $EdgePath"
New-Item -Path $EdgePath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $EdgePath"
$KBFilePath = Save-KB -Name $Name -Path $EdgePath
$EdgeCABFilePath = "$EdgePath\$KBFilePath"
WriteLog "Latest Edge Stable $WindowsArch release saved to $EdgeCABFilePath"
#Extract Edge cab file to same folder as $EdgeFilePath
$EdgeMSIFileName = "MicrosoftEdgeEnterprise$WindowsArch.msi"
$EdgeFullFilePath = "$EdgePath\$EdgeMSIFileName"
WriteLog "Extracting $EdgeCABFilePath"
Invoke-Process Expand "$EdgeCABFilePath -F:*.msi $EdgeFullFilePath"
WriteLog "Extraction complete"
#Modify InstallAppsandSysprep.cmd to add in $KBFilePath on the line after REM Install Edge Stable
WriteLog "Updating $AppsPath\InstallAppsandSysprep.cmd to include Edge Stable $WindowsArch release"
$CmdContent = Get-Content -Path "$AppsPath\InstallAppsandSysprep.cmd"
$UpdatedcmdContent = $CmdContent -replace '^(REM Install Edge Stable)', ("REM Install Edge Stable`r`nd:\Edge\$EdgeMSIFileName /quiet /norestart")
Set-Content -Path "$AppsPath\InstallAppsandSysprep.cmd" -Value $UpdatedcmdContent
WriteLog "Update complete"
}
#Create Apps ISO
WriteLog "Creating $AppsISO file"
New-AppsISO
@@ -1501,8 +1800,6 @@ if ($InstallApps) {
#Create VHDX
try {
#Create dirty.txt file to track if environment is dirty or clean
New-Item -Path .\ -Name "dirty.txt" -ItemType "file" | Out-Null
if ($ISOPath) {
$wimPath = Get-WimFromISO
@@ -1532,6 +1829,67 @@ try {
Add-BootFiles -OsPartitionDriveLetter $osPartitionDriveLetter -SystemPartitionDriveLetter $systemPartitionDriveLetter[1]
#Update latest Cumulative Update
If ($UpdateLatestCU){
WriteLog "`$UpdateLatestCU is set to true, checking for latest CU"
$LatestKB = Get-LatestWindowsKB -WindowsRelease $WindowsRelease
WriteLog "Latest KB for Windows $WindowsRelease found: $LatestKB"
$Name = $LatestKB + " " + $WindowsVersion
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "$LatestKB saved to $KBPath$KBFilePath"
}
#Update Latest .NET Framework
if ($UpdateLatestNet){
Writelog "`$UpdateLatestNet is set to true, checking for latest .NET Framework"
$Name = "Cumulative update for .net framework windows $WindowsRelease $WindowsVersion $Architecture"
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest .NET saved to $KBPath$KBFilePath"
}
#Update Latest Security Platform Update
if($UpdateSecurityPlatform){
WriteLog "`$UpdateSecurityPlatform is set to true, checking for latest Security Platform Update"
$Name = "Windows Security platform definition updates"
#Check if $KBPath exists, if not, create it
If (-not (Test-Path -Path $KBPath)) {
WriteLog "Creating $KBPath"
New-Item -Path $KBPath -ItemType Directory -Force | Out-Null
}
WriteLog "Searching for $Name from Microsoft Update Catalog and saving to $KBPath"
$KBFilePath = Save-KB -Name $Name -Path $KBPath
WriteLog "Latest Security Platform Update saved to $KBPath$KBFilePath"
}
#Add Windows packages
if ($UpdateLatestCU -or $UpdateLatestNet){
try {
WriteLog "Adding KBs to $WindowsPartition"
Add-WindowsPackage -Path $WindowsPartition -PackagePath $KBPath | Out-Null
WriteLog "KBs added to $WindowsPartition"
WriteLog "Removing $KBPath"
Remove-Item -Path $KBPath -Recurse -Force | Out-Null
}
catch {
Write-Host "Adding KB to VHDX failed with error $_"
WriteLog "Adding KB to VHDX failed with error $_"
throw $_
}
}
#Enable Windows Optional Features (e.g. .Net3, etc)
If ($OptionalFeatures) {
$Source = Join-Path (Split-Path $wimpath) "sxs"
@@ -1685,6 +2043,17 @@ catch {
Writelog "VM or vhdx cleanup failed with error $_"
throw $_
}
#Clean up InstallAppsandSysprep.cmd
try {
WriteLog "Cleaning up $AppsPath\InstallAppsandSysprep.cmd"
Clear-InstallAppsandSysprep
}
catch {
Write-Host 'Cleaning up InstallAppsandSysprep.cmd failed'
Writelog "Cleaning up InstallAppsandSysprep.cmd failed with error $_"
throw $_
}
#Create Deployment Media
If ($CreateDeploymentMedia) {
try {