From a3cb93ae038b3cf16bd6e3a566bf319d02702f87 Mon Sep 17 00:00:00 2001 From: Adams Date: Fri, 11 Mar 2022 09:52:05 -0400 Subject: [PATCH 01/14] 1.0.8 - (2022-03-11) Added improved logging with file name of flash utility included. Added copy of log file for BIOS utilities that don't support the logfilename parameter. Signed-off-by: Adams --- Invoke-HPBIOSUpdate.ps1 | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index 8ebaece..53b5c1b 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -31,6 +31,7 @@ 1.0.6 - (2020-02-06) Previous "fix" in 1.0.5 was a mistake, this version corrects it 1.0.7 - (2020-04-23) Added additional logging output when flash utility is being executed including exit code. Removed the LogFileName parameter as the exit code from the flash utility is now embedded in the Invoke-HPBIOSUpdate.log file. + 1.0.8 - (2022-03-11) Added improved logging with file name of flash utility included. Added copy of log file for BIOS utilities that don't support the logfilename parameter. #> [CmdletBinding(SupportsShouldProcess = $true)] @@ -67,7 +68,7 @@ Process { [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] [ValidateNotNullOrEmpty()] - [string]$FileName = "Invoke-HPBIOSUpdate.log" + [string]$FileName = "Invoke-HPBIOSUpdate.log" ) # Determine log file location @@ -109,7 +110,7 @@ Process { $HPBIOSUPDUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPBIOSUPDREC.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec64.exe" } | Select-Object -ExpandProperty FullName } @@ -117,7 +118,7 @@ Process { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFlashUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQFlash.exe" } | Select-Object -ExpandProperty FullName } @@ -127,7 +128,7 @@ Process { if ($HPBIOSUPDUtil -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using HPBIOSUpdRec BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPBIOSUPDUtil BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. $FlashSwitches = " -s -r" $FlashUtility = $HPBIOSUPDUtil @@ -135,7 +136,7 @@ Process { if ($HPFirmwareUpdRec -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using HPFirmwareUpdRec BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPFirmwareUpdRec BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. $FlashSwitches = " -s -r" $FlashUtility = $HPFirmwareUpdRec @@ -143,9 +144,9 @@ Process { if ($HPFlashUtil -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using HPFirmwareUpdRec BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPFlashUtil BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. - $FlashSwitches = " -s -r" + $FlashSwitches = " -s" $FlashUtility = $HPFlashUtil } @@ -167,7 +168,7 @@ Process { try { # Start flash update process Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait -ErrorAction Stop + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 @@ -198,7 +199,7 @@ Process { # Start Bios update process try { Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 @@ -206,5 +207,10 @@ Process { catch [System.Exception] { Write-Warning -Message "An error occured while updating the system BIOS in Full OS phase. Error message: $($_.Exception.Message)"; exit 1 } + + $LogFiles = Get-ChildItem -Path $Path -Filter "*.log" + $LogFiles | ForEach-Object { + Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") + } } -} +} \ No newline at end of file From cc41a671aec2ed536048bbaf4239962c32b70421 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:07:00 -0300 Subject: [PATCH 02/14] Update Invoke-HPBIOSUpdate.ps1 --- Invoke-HPBIOSUpdate.ps1 | 69 +++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index 53b5c1b..c758bfc 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -16,10 +16,10 @@ .NOTES FileName: Invoke-HPBIOSUpdate.ps1 - Author: Lauri Kurvinen / Nickolaj Andersen + Author: Lauri Kurvinen / Nickolaj Andersen / Stuart Adams Contact: @estmi / @NickolajA Created: 2017-09-05 - Updated: 2020-04-23 + Updated: 2022-04-21 Version history: 1.0.0 - (2017-09-05) Script created @@ -32,6 +32,7 @@ 1.0.7 - (2020-04-23) Added additional logging output when flash utility is being executed including exit code. Removed the LogFileName parameter as the exit code from the flash utility is now embedded in the Invoke-HPBIOSUpdate.log file. 1.0.8 - (2022-03-11) Added improved logging with file name of flash utility included. Added copy of log file for BIOS utilities that don't support the logfilename parameter. + 1.0.9 - (2022-04-21) Added ability to specify password and have HpqPwd utility generate a bin file and supply to the flash utility #> [CmdletBinding(SupportsShouldProcess = $true)] @@ -39,7 +40,9 @@ param( [parameter(Mandatory = $true, HelpMessage = "Specify the path containing the HPBIOSUPDREC executable and bios update *.bin -file.")] [ValidateNotNullOrEmpty()] [string]$Path, - + [parameter(Mandatory = $false, HelpMessage = "Specify the BIOS password if necessary.")] + [ValidateNotNullOrEmpty()] + [string]$Password, [parameter(Mandatory = $false, HelpMessage = "Specify the BIOS password filename if necessary (save the password file to the same directory as the script).")] [ValidateNotNullOrEmpty()] [string]$PasswordBin @@ -102,6 +105,27 @@ Process { # Write log file for script execution Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for HP BIOS updates" -Severity 1 + if ($null -ne $Password){ + # Attempt to detect HPQPSWD utility file name + $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd.exe" } | Select-Object -ExpandProperty FullName + + ## Create password bin file + try { + # Start creating bin file process + Write-CMLogEntry -Value "Creating password bin file: $($HPQPswdUtil)" -Severity 1 + $HpqPwdSwitches = "/p`"$($Password)`" /s /f`"password.bin`"" + $HpqPwdProcess = Start-Process -FilePath $HPQPswdUtil -ArgumentList $HpqPwdSwitches -Passthru -Wait -ErrorAction Stop + $PasswordBin = "password.bin" + + # Output Exit Code + Write-CMLogEntry -Value "HpqPswd utility exit code: $($HpqPwdProcess.ExitCode)" -Severity 1 + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occured while creating the bin file. Error message: $($_.Exception.Message)" -Severity 3 #; exit 1 + Remove-Variable PasswordBin + } + } + # Attempt to detect HPBIOSUPDREC utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPBIOSUPDUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPBIOSUPDREC64.exe" } | Select-Object -ExpandProperty FullName @@ -110,7 +134,7 @@ Process { $HPBIOSUPDUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPBIOSUPDREC.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec64.exe" } | Select-Object -ExpandProperty FullName } @@ -118,7 +142,7 @@ Process { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFlashUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQFlash.exe" } | Select-Object -ExpandProperty FullName } @@ -128,15 +152,15 @@ Process { if ($HPBIOSUPDUtil -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using $HPBIOSUPDUtil BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPBIOSUPDUtil BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. - $FlashSwitches = " -s -r" + $FlashSwitches = " -s -r" # WAS " -s -r" $FlashUtility = $HPBIOSUPDUtil } if ($HPFirmwareUpdRec -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using $HPFirmwareUpdRec BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPFirmwareUpdRec BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. $FlashSwitches = " -s -r" $FlashUtility = $HPFirmwareUpdRec @@ -146,7 +170,7 @@ Process { # Set required switches for silent upgrade of the bios and logging Write-CMLogEntry -Value "Using $HPFlashUtil BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. - $FlashSwitches = " -s" + $FlashSwitches = " -s" # WAS " -s -r" $FlashUtility = $HPFlashUtil } @@ -156,7 +180,13 @@ Process { if (-not([System.String]::IsNullOrEmpty($PasswordBin))) { # Add password to the flash bios switches - $FlashSwitches = $FlashSwitches + " -p$($PSScriptRoot)\$($PasswordBin)" + if (-not([System.String]::IsNullOrEmpty($Password))){ + $FlashSwitches = $FlashSwitches + " -p$($Path)\$($PasswordBin)" + } + else { + $FlashSwitches = $FlashSwitches + " -p$($PSScriptRoot)\$($PasswordBin)" + } + Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches)" -Severity 1 } else { @@ -168,7 +198,7 @@ Process { try { # Start flash update process Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait -ErrorAction Stop # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 @@ -199,7 +229,7 @@ Process { # Start Bios update process try { Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 @@ -208,9 +238,14 @@ Process { Write-Warning -Message "An error occured while updating the system BIOS in Full OS phase. Error message: $($_.Exception.Message)"; exit 1 } - $LogFiles = Get-ChildItem -Path $Path -Filter "*.log" - $LogFiles | ForEach-Object { - Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") - } + ## also HpFirmwareUpdRec.txt ? + } + $LogFiles = Get-ChildItem -Path $Path -Filter "*.log" + $LogFiles | ForEach-Object { + Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") } -} \ No newline at end of file + $AdditionalLogFiles = Get-ChildItem -Path $Path -Filter "*.txt" + $AdditionalLogFiles | ForEach-Object { + Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") + } +} From e037930ca3fbef30ea709861cb60937952539760 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Mon, 25 Apr 2022 11:21:44 -0300 Subject: [PATCH 03/14] Update Invoke-HPBIOSUpdate.ps1 Fixed Password -eq $null comparison --- Invoke-HPBIOSUpdate.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index c758bfc..583fa6e 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -105,7 +105,7 @@ Process { # Write log file for script execution Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for HP BIOS updates" -Severity 1 - if ($null -ne $Password){ + if ($Password -ne $null){ # Attempt to detect HPQPSWD utility file name $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd.exe" } | Select-Object -ExpandProperty FullName From f833c8d7f71358eea58a6963695b6d78788cba83 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Mon, 25 Apr 2022 13:11:07 -0300 Subject: [PATCH 04/14] Update Invoke-HPBIOSUpdate.ps1 Changed password comparison again --- Invoke-HPBIOSUpdate.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index 583fa6e..b29c356 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -105,7 +105,7 @@ Process { # Write log file for script execution Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for HP BIOS updates" -Severity 1 - if ($Password -ne $null){ + if (-not([System.String]::IsNullOrEmpty($Password))){ # Attempt to detect HPQPSWD utility file name $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd.exe" } | Select-Object -ExpandProperty FullName From 306be04e6a2bceeceb577e7b49054d18eedc46f5 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Tue, 26 Apr 2022 10:55:21 -0300 Subject: [PATCH 05/14] Update Invoke-HPBIOSUpdate.ps1 Added selection of 64-bit HpqPswd utility if available --- Invoke-HPBIOSUpdate.ps1 | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index b29c356..4c63a4e 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -105,16 +105,30 @@ Process { # Write log file for script execution Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for HP BIOS updates" -Severity 1 - if (-not([System.String]::IsNullOrEmpty($Password))){ - # Attempt to detect HPQPSWD utility file name - $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd.exe" } | Select-Object -ExpandProperty FullName + if (-not([System.String]::IsNullOrEmpty($Password))) { + + # Attempt to detect HPQPSWD utility file name - not all HP packages have a seperate x64 exe for this tool + + if (([Environment]::Is64BitOperatingSystem) -eq $true) { + $PossibleHPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd*.exe" } | Select-Object -ExpandProperty FullName + if ($PossibleHPQPswdUtil.Count -eq 1){ + $HPQPswdUtil = $PossibleHPQPswdUtil # If we found only one tool, select that one + } + else { + $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpqPswd64.exe" } | Select-Object -ExpandProperty FullName + } + } + else { + $HPQPswdUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQPswd.exe" } | Select-Object -ExpandProperty FullName + } + ## Create password bin file try { # Start creating bin file process Write-CMLogEntry -Value "Creating password bin file: $($HPQPswdUtil)" -Severity 1 $HpqPwdSwitches = "/p`"$($Password)`" /s /f`"password.bin`"" - $HpqPwdProcess = Start-Process -FilePath $HPQPswdUtil -ArgumentList $HpqPwdSwitches -Passthru -Wait -ErrorAction Stop + $HpqPwdProcess = Start-Process -FilePath $HPQPswdUtil -ArgumentList $HpqPwdSwitches -PassThru -Wait -ErrorAction Stop $PasswordBin = "password.bin" # Output Exit Code @@ -134,7 +148,7 @@ Process { $HPBIOSUPDUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPBIOSUPDREC.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec64.exe" } | Select-Object -ExpandProperty FullName } @@ -142,7 +156,7 @@ Process { $HPFirmwareUpdRec = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HpFirmwareUpdRec.exe" } | Select-Object -ExpandProperty FullName } - # Attempt to detect HPFirmwareUpdRec utility file name + # Attempt to detect HPFirmwareUpdRec utility file name if (([Environment]::Is64BitOperatingSystem) -eq $true) { $HPFlashUtil = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "HPQFlash.exe" } | Select-Object -ExpandProperty FullName } @@ -152,7 +166,7 @@ Process { if ($HPBIOSUPDUtil -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using $HPBIOSUPDUtil BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPBIOSUPDUtil BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. $FlashSwitches = " -s -r" # WAS " -s -r" $FlashUtility = $HPBIOSUPDUtil @@ -160,7 +174,7 @@ Process { if ($HPFirmwareUpdRec -ne $null) { # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using $HPFirmwareUpdRec BIOS update method" -Severity 1 + Write-CMLogEntry -Value "Using $HPFirmwareUpdRec BIOS update method" -Severity 1 # This -r switch appears to be undocumented, which is a shame really, but this prevents the reboot without exit code. The command now returns a correct exit code and lets ConfigMgr reboot the computer gracefully. $FlashSwitches = " -s -r" $FlashUtility = $HPFirmwareUpdRec @@ -180,7 +194,7 @@ Process { if (-not([System.String]::IsNullOrEmpty($PasswordBin))) { # Add password to the flash bios switches - if (-not([System.String]::IsNullOrEmpty($Password))){ + if (-not([System.String]::IsNullOrEmpty($Password))) { $FlashSwitches = $FlashSwitches + " -p$($Path)\$($PasswordBin)" } else { @@ -198,7 +212,7 @@ Process { try { # Start flash update process Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait -ErrorAction Stop + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 @@ -229,7 +243,7 @@ Process { # Start Bios update process try { Write-CMLogEntry -Value "Running Flash Update: $($FlashUtility)$($FlashSwitches)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait # Output Exit Code Write-CMLogEntry -Value "Flash utility exit code: $($FlashProcess.ExitCode)" -Severity 1 From e236dc52006642f395c445a680408db4043a5806 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Tue, 26 Apr 2022 14:42:21 -0300 Subject: [PATCH 06/14] Update Invoke-HPBIOSUpdate.ps1 Added -Recurse option when retrieving log files to copy to TS log directory --- Invoke-HPBIOSUpdate.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Invoke-HPBIOSUpdate.ps1 b/Invoke-HPBIOSUpdate.ps1 index 4c63a4e..3720613 100644 --- a/Invoke-HPBIOSUpdate.ps1 +++ b/Invoke-HPBIOSUpdate.ps1 @@ -254,11 +254,11 @@ Process { ## also HpFirmwareUpdRec.txt ? } - $LogFiles = Get-ChildItem -Path $Path -Filter "*.log" + $LogFiles = Get-ChildItem -Path $Path -Recurse -Filter "*.log" $LogFiles | ForEach-Object { Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") } - $AdditionalLogFiles = Get-ChildItem -Path $Path -Filter "*.txt" + $AdditionalLogFiles = Get-ChildItem -Path $Path -Recurse -Filter "*.txt" $AdditionalLogFiles | ForEach-Object { Copy-Item -Path $PSItem.FullName -Destination $Script:TSEnvironment.Value("_SMSTSLogPath") } From 20f0db99be6d35997270a2a1ae490782fea2f801 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:31:26 -0300 Subject: [PATCH 07/14] Add files via upload --- Check for BIOS Updates.ps1 | 316 +++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 Check for BIOS Updates.ps1 diff --git a/Check for BIOS Updates.ps1 b/Check for BIOS Updates.ps1 new file mode 100644 index 0000000..a41410a --- /dev/null +++ b/Check for BIOS Updates.ps1 @@ -0,0 +1,316 @@ +# Attempts to construst TSEnvironment object +# Load Microsoft.SMS.TSEnvironment COM object +try { + $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Continue +} +catch [System.Exception] { + #Write-CMLogEntry -Value "Not in a TSEnvironment, we must be testing from Windows" -Severity 1 +} + +#Provides logging in CMTrace style (from sccconfigmgr.com) +if ($TSEnvironment) { + $LogsDirectory = $Script:TSEnvironment.Value("_SMSTSLogPath") + +} +else { + $LogsDirectory = Join-Path $env:SystemRoot "Temp" + +} +function Write-CMLogEntry { + + param ( + [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] + [ValidateNotNullOrEmpty()] + [string]$Value, + [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] + [ValidateNotNullOrEmpty()] + [ValidateSet("1", "2", "3")] + [string]$Severity, + [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] + [ValidateNotNullOrEmpty()] + [string]$FileName = "BIOS Maintenance.log" + ) + # Determine log file location + $LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName + + # Construct time stamp for log entry + if (-not (Test-Path -Path 'variable:global:TimezoneBias')) { + [string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes + if ($TimezoneBias -match "^-") { + $TimezoneBias = $TimezoneBias.Replace('-', '+') + } + else { + $TimezoneBias = '-' + $TimezoneBias + } + } + $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias) + + # Construct date for log entry + $Date = (Get-Date -Format "MM-dd-yyyy") + + # Construct context for log entry + $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) + + # Construct final log entry + $LogText = "" + + # Add value to log file + try { + + Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to append log entry to $FileName. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" + } +} + +function Compare-BIOSVersion { + param ( + [parameter(Mandatory = $false, HelpMessage = "Current available BIOS version.")] + [ValidateNotNullOrEmpty()] + [string]$AvailableBIOSVersion, + [parameter(Mandatory = $false, HelpMessage = "Current available BIOS revision date.")] + [string]$AvailableBIOSReleaseDate, + [parameter(Mandatory = $true, HelpMessage = "Current available BIOS version.")] + [ValidateNotNullOrEmpty()] + [string]$ComputerManufacturer + ) + + if ($ComputerManufacturer -match "Dell") { + # Obtain current BIOS release + $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() + Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release deteced as $($AvailableBIOSVersion)." -Severity 1 + + # Determine Dell BIOS revision format + if ($CurrentBIOSVersion -like "*.*.*") { + # Compare current BIOS release to available + if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + elseif ($CurrentBIOSVersion -like "A*") { + # Compare current BIOS release to available + if ($AvailableBIOSVersion -like "*.*.*") { + # Assume that the bios is new as moving from Axx to x.x.x formats + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + elseif ($AvailableBIOSVersion -gt $CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + } + + if ($ComputerManufacturer -match "Lenovo") { + # Obtain current BIOS release + $CurrentBIOSReleaseDate = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) + Write-CMLogEntry -Value "Current BIOS release date detected as $($CurrentBIOSReleaseDate)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release date detected as $($AvailableBIOSReleaseDate)." -Severity 1 + + # Compare current BIOS release to available + if ($AvailableBIOSReleaseDate -gt $CurrentBIOSReleaseDate) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current date release dated $($CurrentBIOSReleaseDate) will be replaced by release $($AvailableBIOSReleaseDate)." -Severity 1 + } + } + + if ($ComputerManufacturer -match "Hewlett-Packard|HP") { + # Obtain current BIOS release + $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) + + # Update version formatting + $AvailableBIOSVersion = $AvailableBIOSVersion.TrimEnd(".") + $AvailableBIOSVersion = $AvailableBIOSVersion.Split(" ")[0] + + # Detect new versus old BIOS formats + switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { + "*ver*" { + if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { + $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() + $BIOSVersionParseable = $false + } + else { + $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) + $BIOSVersionParseable = $true + } + } + default { + $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" + $BIOSVersionParseable = $true + } + } + + # Output version details + Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release detected as $($AvailableBIOSVersion)." -Severity 1 + + # Compare current BIOS release to available + switch ($BIOSVersionParseable) { + $true { + if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + $false { + if ([System.Int32]::Parse($AvailableBIOSVersion.TrimStart("F.")) -gt [System.Int32]::Parse($CurrentBIOSVersion.TrimStart("F."))) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + } + } +} + + +# Instantiates connection to ASD-Webservice using API key +$URI = $TSEnvironment.Value("ASDWebServiceURI").Replace('/osd', '') +$SecretKey = $TSEnvironment.Value("ASDWebServiceKey") +Write-CMLogEntry -Value "[INFO] URI retrieved: $URI" -Severity 1 + +# $Manufacturer = $WMIObjectWin32Computer.Manufacturer +$WMIObjectWin32Computer = (Get-WmiObject -Class Win32_ComputerSystem) + +$Manufacturer = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Manufacturer).Trim() +switch -Wildcard ($Manufacturer) { + "*Microsoft*" { + $Manufacturer = "Microsoft" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + } + "*HP*" { + $Manufacturer = "HP" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) + $BIOSVersionProperty = 'Version' + } + "*Hewlett-Packard*" { + $Manufacturer = "Hewlett-Packard" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) + $BIOSVersionProperty = 'Version' + } + "*Dell*" { + $Manufacturer = "Dell" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() + $BIOSVersionProperty = 'Version' + } + "*Lenovo*" { + $Manufacturer = "Lenovo" + $Model = (Get-WmiObject -Class "Win32_ComputerSystemProduct" | Select-Object -ExpandProperty Version).Trim() + $CurrentBIOSVersion = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) + $BIOSVersionProperty = 'Description' + } + "*Panasonic*" { + $Manufacturer = "Panasonic Corporation" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + } + "*Viglen*" { + $Manufacturer = "Viglen" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + } + "*AZW*" { + $Manufacturer = "AZW" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + } + "*Fujitsu*" { + $Manufacturer = "Fujitsu" + $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + } + default { + $Manufacturer = $WMIObjectWin32Computer.Manufacturer + $Model = $WMIObjectWin32Computer.Model + } +} + +# Detect new versus old BIOS formats +if ($Manufacturer -match "Hewlett-Packard|HP") { + switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { + "*ver*" { + if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { + $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() + $BIOSVersionParseable = $false + } + else { + $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) + $BIOSVersionParseable = $true + } + } + default { + $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" + $BIOSVersionParseable = $true + } + } +} + + +$APICallParams = @{ + Headers = @{ + "Content-Type" = "application/json" + "Authorization" = "Bearer $($SecretKey)" + } + Method = 'GET' + URI = "$URI/reports/Get-CMBIOSPackage?Model=$Model" + ErrorAction = "SilentlyContinue" +} + +Write-CMLogEntry -Value "[INFO] Calling API for BIOS package information: $APICallParams with model $Model" -Severity 1 +$APIResults = (Invoke-RestMethod @APICallParams) +$AvailableBIOSVersion = $APIResults.$BIOSVersionProperty + +switch ($BIOSVersionProperty) { + 'Description' { + $AvailableBIOSVersion = $AvailableBIOSVersion.Split(':')[2].Split(')')[0] + Compare-BIOSVersion -AvailableBIOSReleaseDate $AvailableBIOSVersion -ComputerManufacturer $Manufacturer + } + 'Version' { + Compare-BIOSVersion -AvailableBIOSVersion $AvailableBIOSVersion -ComputerManufacturer $Manufacturer + } +} + +if ($APIResults.Description -match '=') +{ + Write-CMLogEntry -Value "[INFO] Special BIOS detected. Checking for conditions (Phase or prereq)" -Severity 1 + $Object = $APIResults.Description.Split(")") + $Object | ForEach-Object + { + switch -Wildcard ($PSItem) + { + "*Phase" + { + $Phase = $PSItem.Split('=')[1] + $TSEnvironment.Value("BIOSPhase") = $Phase + Write-CMLogEntry -Value "[INFO] Special BIOS detected. Must run in $Phase" -Severity 1 + } + "*PreReq" + { + $PreReq = $PSItem.Split('=')[1] + $TSEnvironment.Value("BIOSPreReq") = $PreReq + Write-CMLogEntry -Value "[INFO] Special BIOS detected. PreReq Version detected $PreReq" -Severity 1 + } + } + } +} + +Write-CMLogEntry -Value "[INFO] API call results: $AvailableBIOSVersion" -Severity 1 \ No newline at end of file From e753f5e7f85610b252f248072de1085055ea4503 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Wed, 6 Jul 2022 13:35:07 -0300 Subject: [PATCH 08/14] Update Invoke-CMDownloadBIOSPackage.ps1 --- Invoke-CMDownloadBIOSPackage.ps1 | 2210 +++++++++++++++--------------- 1 file changed, 1139 insertions(+), 1071 deletions(-) diff --git a/Invoke-CMDownloadBIOSPackage.ps1 b/Invoke-CMDownloadBIOSPackage.ps1 index 68afdbb..fbe4829 100644 --- a/Invoke-CMDownloadBIOSPackage.ps1 +++ b/Invoke-CMDownloadBIOSPackage.ps1 @@ -71,1252 +71,1320 @@ 3.0.2 - (2020-12-09) - Added new functionality to be able to read a custom Application ID URI, if the default of https://ConfigMgrService is not defined on the ServerApp. 3.0.3 - (2020-12-10) - Fixed issue in WinPE, with addition of baremetal parameter switch (now default) Added BIOSUpdate parameter switch for Full OS deployments + 3.0.4 - (2022-07-05) - Fixed issue detecting older Dells without SKU or fallback SKU #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = "BareMetal")] param ( - [parameter(Mandatory = $true, ParameterSetName = "BareMetal", HelpMessage = "Set the script to operate in 'BareMetal' deployment type mode.")] - [switch]$BareMetal, + [parameter(Mandatory = $true, ParameterSetName = "BareMetal", HelpMessage = "Set the script to operate in 'BareMetal' deployment type mode.")] + [switch]$BareMetal, - [parameter(Mandatory = $true, ParameterSetName = "BIOSUpdate", HelpMessage = "Set the script to operate in 'BIOSUpdate' deployment type mode.")] - [switch]$BIOSUpdate, + [parameter(Mandatory = $true, ParameterSetName = "BIOSUpdate", HelpMessage = "Set the script to operate in 'BIOSUpdate' deployment type mode.")] + [switch]$BIOSUpdate, - [parameter(Mandatory = $true, ParameterSetName = "BIOSUpdate", HelpMessage = "Specify the internal fully qualified domain name of the server hosting the AdminService, e.g. CM01.domain.local.")] - [parameter(Mandatory = $true, ParameterSetName = "BareMetal")] - [parameter(Mandatory = $true, ParameterSetName = "Debug")] - [ValidateNotNullOrEmpty()] - [string]$Endpoint, + [parameter(Mandatory = $true, ParameterSetName = "BIOSUpdate", HelpMessage = "Specify the internal fully qualified domain name of the server hosting the AdminService, e.g. CM01.domain.local.")] + [parameter(Mandatory = $true, ParameterSetName = "BareMetal")] + [parameter(Mandatory = $true, ParameterSetName = "Debug")] + [ValidateNotNullOrEmpty()] + [string]$Endpoint, - [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Set the script to operate in 'DebugMode' deployment type mode.")] - [switch]$DebugMode, + [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Set the script to operate in 'DebugMode' deployment type mode.")] + [switch]$DebugMode, - [parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Specify the service account user name used for authenticating against the AdminService endpoint.")] - [ValidateNotNullOrEmpty()] - [string]$UserName = "", + [parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Specify the service account user name used for authenticating against the AdminService endpoint.")] + [ValidateNotNullOrEmpty()] + [string]$UserName = "", - [parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Specify the service account password used for authenticating against the AdminService endpoint.")] - [ValidateNotNullOrEmpty()] - [string]$Password = "", + [parameter(Mandatory = $true, ParameterSetName = "Debug", HelpMessage = "Specify the service account password used for authenticating against the AdminService endpoint.")] + [ValidateNotNullOrEmpty()] + [string]$Password = "", - [parameter(Mandatory = $false, ParameterSetName = "BIOSUpdate", HelpMessage = "Define a filter used when calling the AdminService to only return objects matching the filter.")] - [parameter(Mandatory = $false, ParameterSetName = "BareMetal")] - [ValidateNotNullOrEmpty()] - [string]$Filter = "BIOS", + [parameter(Mandatory = $false, ParameterSetName = "BIOSUpdate", HelpMessage = "Define a filter used when calling the AdminService to only return objects matching the filter.")] + [parameter(Mandatory = $false, ParameterSetName = "BareMetal")] + [ValidateNotNullOrEmpty()] + [string]$Filter = "BIOS", - [parameter(Mandatory = $false, ParameterSetName = "BIOSUpdate", HelpMessage = "Define the operational mode, either Production or Pilot, for when calling ConfigMgr WebService to only return objects matching the selected operational mode.")] - [parameter(Mandatory = $false, ParameterSetName = "BareMetal")] - [parameter(Mandatory = $true, ParameterSetName = "Debug")] - [ValidateNotNullOrEmpty()] - [ValidateSet("Production", "Pilot")] - [string]$OperationalMode = "Production", + [parameter(Mandatory = $false, ParameterSetName = "BIOSUpdate", HelpMessage = "Define the operational mode, either Production or Pilot, for when calling ConfigMgr WebService to only return objects matching the selected operational mode.")] + [parameter(Mandatory = $false, ParameterSetName = "BareMetal")] + [parameter(Mandatory = $true, ParameterSetName = "Debug")] + [ValidateNotNullOrEmpty()] + [ValidateSet("Production", "Pilot")] + [string]$OperationalMode = "Production", - [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer manufacturer when running in debug mode.")] - [ValidateNotNullOrEmpty()] - [ValidateSet("Hewlett-Packard", "HP", "Dell", "Lenovo", "Microsoft", "Fujitsu", "Panasonic", "Viglen", "AZW")] - [string]$Manufacturer, + [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer manufacturer when running in debug mode.")] + [ValidateNotNullOrEmpty()] + [ValidateSet("Hewlett-Packard", "HP", "Dell", "Lenovo", "Microsoft", "Fujitsu", "Panasonic", "Viglen", "AZW")] + [string]$Manufacturer, - [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer model when running in debug mode.")] - [ValidateNotNullOrEmpty()] - [string]$ComputerModel, + [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected computer model when running in debug mode.")] + [ValidateNotNullOrEmpty()] + [string]$ComputerModel, - [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected SystemSKU when running in debug mode.")] - [ValidateNotNullOrEmpty()] - [string]$SystemSKU + [parameter(Mandatory = $false, ParameterSetName = "Debug", HelpMessage = "Override the automatically detected SystemSKU when running in debug mode.")] + [ValidateNotNullOrEmpty()] + [string]$SystemSKU ) Begin { - # Load Microsoft.SMS.TSEnvironment COM object - if ($PSCmdLet.ParameterSetName -notlike "Debug") { - try { - $TSEnvironment = New-Object -ComObject "Microsoft.SMS.TSEnvironment" -ErrorAction Stop - } catch [System.Exception] { - Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object"; exit - } - } + # Load Microsoft.SMS.TSEnvironment COM object + if ($PSCmdLet.ParameterSetName -notlike "Debug") { + try { + $TSEnvironment = New-Object -ComObject "Microsoft.SMS.TSEnvironment" -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object"; exit + } + } - # Set Security Protocol (TLS) - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + # Set Security Protocol (TLS) + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } Process { - # Set Log Path - switch ($PSCmdLet.ParameterSetName) { - "Debug" { - $LogsDirectory = Join-Path -Path $env:SystemRoot -ChildPath "Temp" - } - default { - $LogsDirectory = $Script:TSEnvironment.Value("_SMSTSLogPath") - } - } + # Set Log Path + switch ($PSCmdLet.ParameterSetName) { + "Debug" { + $LogsDirectory = Join-Path -Path $env:SystemRoot -ChildPath "Temp" + } + default { + $LogsDirectory = $Script:TSEnvironment.Value("_SMSTSLogPath") + } + } - # Functions - function Write-CMLogEntry { - param ( - [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] - [ValidateNotNullOrEmpty()] - [string]$Value, + # Functions + function Write-CMLogEntry { + param ( + [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] + [ValidateNotNullOrEmpty()] + [string]$Value, - [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] - [ValidateNotNullOrEmpty()] - [ValidateSet("1", "2", "3")] - [string]$Severity, + [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] + [ValidateNotNullOrEmpty()] + [ValidateSet("1", "2", "3")] + [string]$Severity, - [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] - [ValidateNotNullOrEmpty()] - [string]$FileName = "ApplyBIOSPackage.log" - ) - # Determine log file location - $LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName + [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] + [ValidateNotNullOrEmpty()] + [string]$FileName = "ApplyBIOSPackage.log" + ) + # Determine log file location + $LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName - # Construct time stamp for log entry - if (-not (Test-Path -Path 'variable:global:TimezoneBias')) { - [string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes - if ($TimezoneBias -match "^-") { - $TimezoneBias = $TimezoneBias.Replace('-', '+') - } else { - $TimezoneBias = '-' + $TimezoneBias - } - } - $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias) + # Construct time stamp for log entry + if (-not (Test-Path -Path 'variable:global:TimezoneBias')) { + [string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes + if ($TimezoneBias -match "^-") { + $TimezoneBias = $TimezoneBias.Replace('-', '+') + } + else { + $TimezoneBias = '-' + $TimezoneBias + } + } + $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias) - # Construct date for log entry - $Date = (Get-Date -Format "MM-dd-yyyy") + # Construct date for log entry + $Date = (Get-Date -Format "MM-dd-yyyy") - # Construct context for log entry - $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) + # Construct context for log entry + $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - # Construct final log entry - $LogText = "" + # Construct final log entry + $LogText = "" - # Add value to log file - try { - Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop - } catch [System.Exception] { - Write-Warning -Message "Unable to append log entry to ApplyBIOSPackage.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" - } - } + # Add value to log file + try { + Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to append log entry to ApplyBIOSPackage.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" + } + } - function Invoke-Executable { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the file name or path of the executable to be invoked, including the extension")] - [ValidateNotNullOrEmpty()] - [string]$FilePath, + function Invoke-Executable { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the file name or path of the executable to be invoked, including the extension")] + [ValidateNotNullOrEmpty()] + [string]$FilePath, - [parameter(Mandatory = $false, HelpMessage = "Specify arguments that will be passed to the executable")] - [ValidateNotNull()] - [string]$Arguments - ) + [parameter(Mandatory = $false, HelpMessage = "Specify arguments that will be passed to the executable")] + [ValidateNotNull()] + [string]$Arguments + ) - # Construct a hash-table for default parameter splatting - $SplatArgs = @{ - FilePath = $FilePath - NoNewWindow = $true - Passthru = $true - ErrorAction = "Stop" - } + # Construct a hash-table for default parameter splatting + $SplatArgs = @{ + FilePath = $FilePath + NoNewWindow = $true + Passthru = $true + ErrorAction = "Stop" + } - # Add ArgumentList param if present - if (-not ([System.String]::IsNullOrEmpty($Arguments))) { - $SplatArgs.Add("ArgumentList", $Arguments) - } + # Add ArgumentList param if present + if (-not ([System.String]::IsNullOrEmpty($Arguments))) { + $SplatArgs.Add("ArgumentList", $Arguments) + } - # Invoke executable and wait for process to exit - try { - $Invocation = Start-Process @SplatArgs - $Handle = $Invocation.Handle - $Invocation.WaitForExit() - } catch [System.Exception] { - Write-Warning -Message $_.Exception.Message; break - } + # Invoke executable and wait for process to exit + try { + $Invocation = Start-Process @SplatArgs + $Handle = $Invocation.Handle + $Invocation.WaitForExit() + } + catch [System.Exception] { + Write-Warning -Message $_.Exception.Message; break + } - return $Invocation.ExitCode - } + return $Invocation.ExitCode + } - function Invoke-CMDownloadContent { - param ( - [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify a PackageID that will be downloaded.")] - [Parameter(ParameterSetName = "CustomPath")] - [ValidateNotNullOrEmpty()] - [ValidatePattern("^[A-Z0-9]{3}[A-F0-9]{5}$")] - [string]$PackageID, + function Invoke-CMDownloadContent { + param ( + [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify a PackageID that will be downloaded.")] + [Parameter(ParameterSetName = "CustomPath")] + [ValidateNotNullOrEmpty()] + [ValidatePattern("^[A-Z0-9]{3}[A-F0-9]{5}$")] + [string]$PackageID, - [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify the download location type.")] - [Parameter(ParameterSetName = "CustomPath")] - [ValidateNotNullOrEmpty()] - [ValidateSet("Custom", "TSCache", "CCMCache")] - [string]$DestinationLocationType, + [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Specify the download location type.")] + [Parameter(ParameterSetName = "CustomPath")] + [ValidateNotNullOrEmpty()] + [ValidateSet("Custom", "TSCache", "CCMCache")] + [string]$DestinationLocationType, - [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Save the download location to the specified variable name.")] - [Parameter(ParameterSetName = "CustomPath")] - [ValidateNotNullOrEmpty()] - [string]$DestinationVariableName, + [parameter(Mandatory = $true, ParameterSetName = "NoPath", HelpMessage = "Save the download location to the specified variable name.")] + [Parameter(ParameterSetName = "CustomPath")] + [ValidateNotNullOrEmpty()] + [string]$DestinationVariableName, - [parameter(Mandatory = $true, ParameterSetName = "CustomPath", HelpMessage = "When location type is specified as Custom, specify the custom path.")] - [ValidateNotNullOrEmpty()] - [string]$CustomLocationPath - ) - # Set OSDDownloadDownloadPackages - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to: $($PackageID)" -Severity 1 - $TSEnvironment.Value("OSDDownloadDownloadPackages") = "$($PackageID)" + [parameter(Mandatory = $true, ParameterSetName = "CustomPath", HelpMessage = "When location type is specified as Custom, specify the custom path.")] + [ValidateNotNullOrEmpty()] + [string]$CustomLocationPath + ) + # Set OSDDownloadDownloadPackages + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to: $($PackageID)" -Severity 1 + $TSEnvironment.Value("OSDDownloadDownloadPackages") = "$($PackageID)" - # Set OSDDownloadDestinationLocationType - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to: $($DestinationLocationType)" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationLocationType") = "$($DestinationLocationType)" + # Set OSDDownloadDestinationLocationType + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to: $($DestinationLocationType)" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationLocationType") = "$($DestinationLocationType)" - # Set OSDDownloadDestinationVariable - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to: $($DestinationVariableName)" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationVariable") = "$($DestinationVariableName)" + # Set OSDDownloadDestinationVariable + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to: $($DestinationVariableName)" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationVariable") = "$($DestinationVariableName)" - # Set OSDDownloadDestinationPath - if ($DestinationLocationType -like "Custom") { - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to: $($CustomLocationPath)" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationPath") = "$($CustomLocationPath)" - } + # Set OSDDownloadDestinationPath + if ($DestinationLocationType -like "Custom") { + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to: $($CustomLocationPath)" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationPath") = "$($CustomLocationPath)" + } - # Set SMSTSDownloadRetryCount to 1000 to overcome potential BranchCache issue that will cause 'SendWinHttpRequest failed. 80072efe' - $TSEnvironment.Value("SMSTSDownloadRetryCount") = 1000 + # Set SMSTSDownloadRetryCount to 1000 to overcome potential BranchCache issue that will cause 'SendWinHttpRequest failed. 80072efe' + $TSEnvironment.Value("SMSTSDownloadRetryCount") = 1000 - # Invoke download of package content - try { - if ($TSEnvironment.Value("_SMSTSInWinPE") -eq $false) { - Write-CMLogEntry -Value " - Starting package content download process (FullOS), this might take some time" -Severity 1 - $ReturnCode = Invoke-Executable -FilePath (Join-Path -Path $env:windir -ChildPath "CCM\OSDDownloadContent.exe") - } else { - Write-CMLogEntry -Value " - Starting package content download process (WinPE), this might take some time" -Severity 1 - $ReturnCode = Invoke-Executable -FilePath "OSDDownloadContent.exe" - } + # Invoke download of package content + try { + if ($TSEnvironment.Value("_SMSTSInWinPE") -eq $false) { + Write-CMLogEntry -Value " - Starting package content download process (FullOS), this might take some time" -Severity 1 + $ReturnCode = Invoke-Executable -FilePath (Join-Path -Path $env:windir -ChildPath "CCM\OSDDownloadContent.exe") + } + else { + Write-CMLogEntry -Value " - Starting package content download process (WinPE), this might take some time" -Severity 1 + $ReturnCode = Invoke-Executable -FilePath "OSDDownloadContent.exe" + } - # Reset SMSTSDownloadRetryCount to 5 after attempted download - $TSEnvironment.Value("SMSTSDownloadRetryCount") = 5 + # Reset SMSTSDownloadRetryCount to 5 after attempted download + $TSEnvironment.Value("SMSTSDownloadRetryCount") = 5 - # Match on return code - if ($ReturnCode -eq 0) { - Write-CMLogEntry -Value " - Successfully downloaded package content with PackageID: $($PackageID)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Failed to download package content with PackageID '$($PackageID)'. Return code was: $($ReturnCode)" -Severity 3 + # Match on return code + if ($ReturnCode -eq 0) { + Write-CMLogEntry -Value " - Successfully downloaded package content with PackageID: $($PackageID)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Failed to download package content with PackageID '$($PackageID)'. Return code was: $($ReturnCode)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } catch [System.Exception] { - Write-CMLogEntry -Value " - An error occurred while attempting to download package content. Error message: $($_.Exception.Message)" -Severity 3 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + catch [System.Exception] { + Write-CMLogEntry -Value " - An error occurred while attempting to download package content. Error message: $($_.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } - return $ReturnCode - } + return $ReturnCode + } - function Invoke-CMResetDownloadContentVariables { - # Set OSDDownloadDownloadPackages - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to a blank value" -Severity 1 - $TSEnvironment.Value("OSDDownloadDownloadPackages") = [System.String]::Empty + function Invoke-CMResetDownloadContentVariables { + # Set OSDDownloadDownloadPackages + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDownloadPackages to a blank value" -Severity 1 + $TSEnvironment.Value("OSDDownloadDownloadPackages") = [System.String]::Empty - # Set OSDDownloadDestinationLocationType - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to a blank value" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationLocationType") = [System.String]::Empty + # Set OSDDownloadDestinationLocationType + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationLocationType to a blank value" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationLocationType") = [System.String]::Empty - # Set OSDDownloadDestinationVariable - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to a blank value" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationVariable") = [System.String]::Empty + # Set OSDDownloadDestinationVariable + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationVariable to a blank value" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationVariable") = [System.String]::Empty - # Set OSDDownloadDestinationPath - Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to a blank value" -Severity 1 - $TSEnvironment.Value("OSDDownloadDestinationPath") = [System.String]::Empty - } + # Set OSDDownloadDestinationPath + Write-CMLogEntry -Value " - Setting task sequence variable OSDDownloadDestinationPath to a blank value" -Severity 1 + $TSEnvironment.Value("OSDDownloadDestinationPath") = [System.String]::Empty + } - function New-TerminatingErrorRecord { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the exception message details.")] - [ValidateNotNullOrEmpty()] - [string]$Message, + function New-TerminatingErrorRecord { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the exception message details.")] + [ValidateNotNullOrEmpty()] + [string]$Message, - [parameter(Mandatory = $false, HelpMessage = "Specify the violation exception causing the error.")] - [ValidateNotNullOrEmpty()] - [string]$Exception = "System.Management.Automation.RuntimeException", + [parameter(Mandatory = $false, HelpMessage = "Specify the violation exception causing the error.")] + [ValidateNotNullOrEmpty()] + [string]$Exception = "System.Management.Automation.RuntimeException", - [parameter(Mandatory = $false, HelpMessage = "Specify the error category of the exception causing the error.")] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.ErrorCategory]$ErrorCategory = [System.Management.Automation.ErrorCategory]::NotImplemented, + [parameter(Mandatory = $false, HelpMessage = "Specify the error category of the exception causing the error.")] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.ErrorCategory]$ErrorCategory = [System.Management.Automation.ErrorCategory]::NotImplemented, - [parameter(Mandatory = $false, HelpMessage = "Specify the target object causing the error.")] - [ValidateNotNullOrEmpty()] - [string]$TargetObject = ([string]::Empty) - ) - # Construct new error record to be returned from function based on parameter inputs - $SystemException = New-Object -TypeName $Exception -ArgumentList $Message - $ErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList @($SystemException, $ErrorID, $ErrorCategory, $TargetObject) + [parameter(Mandatory = $false, HelpMessage = "Specify the target object causing the error.")] + [ValidateNotNullOrEmpty()] + [string]$TargetObject = ([string]::Empty) + ) + # Construct new error record to be returned from function based on parameter inputs + $SystemException = New-Object -TypeName $Exception -ArgumentList $Message + $ErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList @($SystemException, $ErrorID, $ErrorCategory, $TargetObject) - # Handle return value - return $ErrorRecord - } + # Handle return value + return $ErrorRecord + } - function Get-DeploymentType { - switch ($PSCmdlet.ParameterSetName) { - "XMLPackage" { - # Set required variables for XMLPackage parameter set - $Script:DeploymentMode = $Script:XMLDeploymentType - $Script:PackageSource = "XML Package Logic file" + function Get-DeploymentType { + switch ($PSCmdlet.ParameterSetName) { + "XMLPackage" { + # Set required variables for XMLPackage parameter set + $Script:DeploymentMode = $Script:XMLDeploymentType + $Script:PackageSource = "XML Package Logic file" - # Define the path for the pre-downloaded XML Package Logic file called DriverPackages.xml - $script:XMLPackageLogicFile = (Join-Path -Path $TSEnvironment.Value("MDMXMLPackage01") -ChildPath "DriverPackages.xml") - if (-not (Test-Path -Path $XMLPackageLogicFile)) { - Write-CMLogEntry -Value " - Failed to locate required 'DriverPackages.xml' logic file for XMLPackage deployment type, ensure it has been pre-downloaded in a Download Package Content step before running this script" -Severity 3 + # Define the path for the pre-downloaded XML Package Logic file called DriverPackages.xml + $script:XMLPackageLogicFile = (Join-Path -Path $TSEnvironment.Value("MDMXMLPackage01") -ChildPath "DriverPackages.xml") + if (-not (Test-Path -Path $XMLPackageLogicFile)) { + Write-CMLogEntry -Value " - Failed to locate required 'DriverPackages.xml' logic file for XMLPackage deployment type, ensure it has been pre-downloaded in a Download Package Content step before running this script" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - default { - $Script:DeploymentMode = $Script:PSCmdlet.ParameterSetName - $Script:PackageSource = "AdminService" - } - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + default { + $Script:DeploymentMode = $Script:PSCmdlet.ParameterSetName + $Script:PackageSource = "AdminService" + } + } + } - function ConvertTo-ObfuscatedUserName { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the user name string to be obfuscated for log output.")] - [ValidateNotNullOrEmpty()] - [string]$InputObject - ) - # Convert input object to a character array - $UserNameArray = $InputObject.ToCharArray() + function ConvertTo-ObfuscatedUserName { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the user name string to be obfuscated for log output.")] + [ValidateNotNullOrEmpty()] + [string]$InputObject + ) + # Convert input object to a character array + $UserNameArray = $InputObject.ToCharArray() - # Loop through each character obfuscate every second item, with exceptions of the @ character if present - for ($i = 0; $i -lt $UserNameArray.Count; $i++) { - if ($UserNameArray[$i] -notmatch "@") { - if ($i % 2) { - $UserNameArray[$i] = "*" - } - } - } + # Loop through each character obfuscate every second item, with exceptions of the @ character if present + for ($i = 0; $i -lt $UserNameArray.Count; $i++) { + if ($UserNameArray[$i] -notmatch "@") { + if ($i % 2) { + $UserNameArray[$i] = "*" + } + } + } - # Join character array and return value - return -join @($UserNameArray) - } + # Join character array and return value + return -join @($UserNameArray) + } - function Test-AdminServiceData { - # Validate correct value have been either set as a TS environment variable or passed as parameter input for service account user name used to authenticate against the AdminService - if ([string]::IsNullOrEmpty($Script:UserName)) { - switch ($PSCmdLet.ParameterSetName) { - "Debug" { - Write-CMLogEntry -Value " - Required service account user name could not be determined from parameter input" -Severity 3 + function Test-AdminServiceData { + # Validate correct value have been either set as a TS environment variable or passed as parameter input for service account user name used to authenticate against the AdminService + if ([string]::IsNullOrEmpty($Script:UserName)) { + switch ($PSCmdLet.ParameterSetName) { + "Debug" { + Write-CMLogEntry -Value " - Required service account user name could not be determined from parameter input" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - default { - # Attempt to read TSEnvironment variable MDMUserName - $Script:UserName = $TSEnvironment.Value("MDMUserName") - if (-not ([string]::IsNullOrEmpty($Script:UserName))) { - # Obfuscate user name - $ObfuscatedUserName = ConvertTo-ObfuscatedUserName -InputObject $Script:UserName + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + default { + # Attempt to read TSEnvironment variable MDMUserName + $Script:UserName = $TSEnvironment.Value("MDMUserName") + if (-not ([string]::IsNullOrEmpty($Script:UserName))) { + # Obfuscate user name + $ObfuscatedUserName = ConvertTo-ObfuscatedUserName -InputObject $Script:UserName - Write-CMLogEntry -Value " - Successfully read service account user name from TS environment variable 'MDMUserName': $($ObfuscatedUserName)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Required service account user name could not be determined from TS environment variable" -Severity 3 + Write-CMLogEntry -Value " - Successfully read service account user name from TS environment variable 'MDMUserName': $($ObfuscatedUserName)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Required service account user name could not be determined from TS environment variable" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } - } else { - # Obfuscate user name - $ObfuscatedUserName = ConvertTo-ObfuscatedUserName -InputObject $Script:UserName + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } + } + else { + # Obfuscate user name + $ObfuscatedUserName = ConvertTo-ObfuscatedUserName -InputObject $Script:UserName - Write-CMLogEntry -Value " - Successfully read service account user name from parameter input: $($ObfuscatedUserName)" -Severity 1 - } + Write-CMLogEntry -Value " - Successfully read service account user name from parameter input: $($ObfuscatedUserName)" -Severity 1 + } - # Validate correct value have been either set as a TS environment variable or passed as parameter input for service account password used to authenticate against the AdminService - if ([string]::IsNullOrEmpty($Script:Password)) { - switch ($Script:PSCmdLet.ParameterSetName) { - "Debug" { - Write-CMLogEntry -Value " - Required service account password could not be determined from parameter input" -Severity 3 - } - default { - # Attempt to read TSEnvironment variable MDMPassword - $Script:Password = $TSEnvironment.Value("MDMPassword") - if (-not ([string]::IsNullOrEmpty($Script:Password))) { - Write-CMLogEntry -Value " - Successfully read service account password from TS environment variable 'MDMPassword': ********" -Severity 1 - } else { - Write-CMLogEntry -Value " - Required service account password could not be determined from TS environment variable" -Severity 3 + # Validate correct value have been either set as a TS environment variable or passed as parameter input for service account password used to authenticate against the AdminService + if ([string]::IsNullOrEmpty($Script:Password)) { + switch ($Script:PSCmdLet.ParameterSetName) { + "Debug" { + Write-CMLogEntry -Value " - Required service account password could not be determined from parameter input" -Severity 3 + } + default { + # Attempt to read TSEnvironment variable MDMPassword + $Script:Password = $TSEnvironment.Value("MDMPassword") + if (-not ([string]::IsNullOrEmpty($Script:Password))) { + Write-CMLogEntry -Value " - Successfully read service account password from TS environment variable 'MDMPassword': ********" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Required service account password could not be determined from TS environment variable" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } - } else { - Write-CMLogEntry -Value " - Successfully read service account password from parameter input: ********" -Severity 1 - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } + } + else { + Write-CMLogEntry -Value " - Successfully read service account password from parameter input: ********" -Severity 1 + } - # Validate that if determined AdminService endpoint type is external, that additional required TS environment variables are available - if ($Script:AdminServiceEndpointType -like "External") { - if ($Script:PSCmdLet.ParameterSetName -notlike "Debug") { - # Attempt to read TSEnvironment variable MDMExternalEndpoint - $Script:ExternalEndpoint = $TSEnvironment.Value("MDMExternalEndpoint") - if (-not ([string]::IsNullOrEmpty($Script:ExternalEndpoint))) { - Write-CMLogEntry -Value " - Successfully read external endpoint address for AdminService through CMG from TS environment variable 'MDMExternalEndpoint': $($Script:ExternalEndpoint)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Required external endpoint address for AdminService through CMG could not be determined from TS environment variable" -Severity 3 + # Validate that if determined AdminService endpoint type is external, that additional required TS environment variables are available + if ($Script:AdminServiceEndpointType -like "External") { + if ($Script:PSCmdLet.ParameterSetName -notlike "Debug") { + # Attempt to read TSEnvironment variable MDMExternalEndpoint + $Script:ExternalEndpoint = $TSEnvironment.Value("MDMExternalEndpoint") + if (-not ([string]::IsNullOrEmpty($Script:ExternalEndpoint))) { + Write-CMLogEntry -Value " - Successfully read external endpoint address for AdminService through CMG from TS environment variable 'MDMExternalEndpoint': $($Script:ExternalEndpoint)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Required external endpoint address for AdminService through CMG could not be determined from TS environment variable" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } - # Attempt to read TSEnvironment variable MDMClientID - $Script:ClientID = $TSEnvironment.Value("MDMClientID") - if (-not ([string]::IsNullOrEmpty($Script:ClientID))) { - Write-CMLogEntry -Value " - Successfully read client identification for AdminService through CMG from TS environment variable 'MDMClientID': $($Script:ClientID)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Required client identification for AdminService through CMG could not be determined from TS environment variable" -Severity 3 + # Attempt to read TSEnvironment variable MDMClientID + $Script:ClientID = $TSEnvironment.Value("MDMClientID") + if (-not ([string]::IsNullOrEmpty($Script:ClientID))) { + Write-CMLogEntry -Value " - Successfully read client identification for AdminService through CMG from TS environment variable 'MDMClientID': $($Script:ClientID)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Required client identification for AdminService through CMG could not be determined from TS environment variable" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } - # Attempt to read TSEnvironment variable MDMTenantName - $Script:TenantName = $TSEnvironment.Value("MDMTenantName") - if (-not ([string]::IsNullOrEmpty($Script:TenantName))) { - Write-CMLogEntry -Value " - Successfully read client identification for AdminService through CMG from TS environment variable 'MDMTenantName': $($Script:TenantName)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Required client identification for AdminService through CMG could not be determined from TS environment variable" -Severity 3 + # Attempt to read TSEnvironment variable MDMTenantName + $Script:TenantName = $TSEnvironment.Value("MDMTenantName") + if (-not ([string]::IsNullOrEmpty($Script:TenantName))) { + Write-CMLogEntry -Value " - Successfully read client identification for AdminService through CMG from TS environment variable 'MDMTenantName': $($Script:TenantName)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Required client identification for AdminService through CMG could not be determined from TS environment variable" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } - # Attempt to read TSEnvironment variable MDMApplicationIDURI - $Script:ApplicationIDURI = $TSEnvironment.Value("MDMApplicationIDURI") - if (-not ([string]::IsNullOrEmpty($Script:ApplicationIDURI))) { - Write-CMLogEntry -Value " - Successfully read Application ID URI from TS environment variable 'MDMApplicationIDURI': $($Script:ApplicationIDURI)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Using standard Application ID URI value: https://ConfigMgrService" -Severity 2 - $Script:ApplicationIDURI = "https://ConfigMgrService" - } - } - } - } + # Attempt to read TSEnvironment variable MDMApplicationIDURI + $Script:ApplicationIDURI = $TSEnvironment.Value("MDMApplicationIDURI") + if (-not ([string]::IsNullOrEmpty($Script:ApplicationIDURI))) { + Write-CMLogEntry -Value " - Successfully read Application ID URI from TS environment variable 'MDMApplicationIDURI': $($Script:ApplicationIDURI)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Using standard Application ID URI value: https://ConfigMgrService" -Severity 2 + $Script:ApplicationIDURI = "https://ConfigMgrService" + } + } + } + } - function Get-AdminServiceEndpointType { - switch ($Script:DeploymentMode) { - "BareMetal" { - $SMSInWinPE = $TSEnvironment.Value("_SMSTSInWinPE") - if ($SMSInWinPE -eq $true) { - Write-CMLogEntry -Value " - Detected that script was running within a task sequence in WinPE phase, automatically configuring AdminService endpoint type" -Severity 1 - $Script:AdminServiceEndpointType = "Internal" - } else { - Write-CMLogEntry -Value " - Detected that script was not running in WinPE of a bare metal deployment type, this is not a supported scenario" -Severity 3 + function Get-AdminServiceEndpointType { + switch ($Script:DeploymentMode) { + "BareMetal" { + $SMSInWinPE = $TSEnvironment.Value("_SMSTSInWinPE") + if ($SMSInWinPE -eq $true) { + Write-CMLogEntry -Value " - Detected that script was running within a task sequence in WinPE phase, automatically configuring AdminService endpoint type" -Severity 1 + $Script:AdminServiceEndpointType = "Internal" + } + else { + Write-CMLogEntry -Value " - Detected that script was not running in WinPE of a bare metal deployment type, this is not a supported scenario" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - "Debug" { - $Script:AdminServiceEndpointType = "Internal" - } - default { - Write-CMLogEntry -Value " - Attempting to determine AdminService endpoint type based on current active Management Point candidates and from ClientInfo class" -Severity 1 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + "Debug" { + $Script:AdminServiceEndpointType = "Internal" + } + default { + Write-CMLogEntry -Value " - Attempting to determine AdminService endpoint type based on current active Management Point candidates and from ClientInfo class" -Severity 1 - # Determine active MP candidates and if - $ActiveMPCandidates = Get-WmiObject -Namespace "root\ccm\LocationServices" -Class "SMS_ActiveMPCandidate" - $ActiveMPInternalCandidatesCount = ($ActiveMPCandidates | Where-Object { - $PSItem.Type -like "Assigned" - } | Measure-Object).Count - $ActiveMPExternalCandidatesCount = ($ActiveMPCandidates | Where-Object { - $PSItem.Type -like "Internet" - } | Measure-Object).Count + # Determine active MP candidates and if + $ActiveMPCandidates = Get-WmiObject -Namespace "root\ccm\LocationServices" -Class "SMS_ActiveMPCandidate" + $ActiveMPInternalCandidatesCount = ($ActiveMPCandidates | Where-Object { + $PSItem.Type -like "Assigned" + } | Measure-Object).Count + $ActiveMPExternalCandidatesCount = ($ActiveMPCandidates | Where-Object { + $PSItem.Type -like "Internet" + } | Measure-Object).Count - # Determine if ConfigMgr client has detected if the computer is currently on internet or intranet - $CMClientInfo = Get-WmiObject -Namespace "root\ccm" -Class "ClientInfo" - switch ($CMClientInfo.InInternet) { - $true { - if ($ActiveMPExternalCandidatesCount -ge 1) { - $Script:AdminServiceEndpointType = "External" - } else { - Write-CMLogEntry -Value " - Detected as an Internet client but unable to determine External AdminService endpoint, bailing out" -Severity 3 + # Determine if ConfigMgr client has detected if the computer is currently on internet or intranet + $CMClientInfo = Get-WmiObject -Namespace "root\ccm" -Class "ClientInfo" + switch ($CMClientInfo.InInternet) { + $true { + if ($ActiveMPExternalCandidatesCount -ge 1) { + $Script:AdminServiceEndpointType = "External" + } + else { + Write-CMLogEntry -Value " - Detected as an Internet client but unable to determine External AdminService endpoint, bailing out" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - $false { - if ($ActiveMPInternalCandidatesCount -ge 1) { - $Script:AdminServiceEndpointType = "Internal" - } else { - Write-CMLogEntry -Value " - Detected as an Intranet client but unable to determine Internal AdminService endpoint, bailing out" -Severity 3 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + $false { + if ($ActiveMPInternalCandidatesCount -ge 1) { + $Script:AdminServiceEndpointType = "Internal" + } + else { + Write-CMLogEntry -Value " - Detected as an Intranet client but unable to determine Internal AdminService endpoint, bailing out" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } - } - } - Write-CMLogEntry -Value " - Determined AdminService endpoint type as: $($AdminServiceEndpointType)" -Severity 1 - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } + } + } + Write-CMLogEntry -Value " - Determined AdminService endpoint type as: $($AdminServiceEndpointType)" -Severity 1 + } - function Set-AdminServiceEndpointURL { - switch ($Script:AdminServiceEndpointType) { - "Internal" { - $Script:AdminServiceURL = "https://{0}/AdminService/wmi" -f $Endpoint - } - "External" { - $Script:AdminServiceURL = "{0}/wmi" -f $ExternalEndpoint - } - } - Write-CMLogEntry -Value " - Setting 'AdminServiceURL' variable to: $($Script:AdminServiceURL)" -Severity 1 - } + function Set-AdminServiceEndpointURL { + switch ($Script:AdminServiceEndpointType) { + "Internal" { + $Script:AdminServiceURL = "https://{0}/AdminService/wmi" -f $Endpoint + } + "External" { + $Script:AdminServiceURL = "{0}/wmi" -f $ExternalEndpoint + } + } + Write-CMLogEntry -Value " - Setting 'AdminServiceURL' variable to: $($Script:AdminServiceURL)" -Severity 1 + } - function Install-AuthModule { - # Determine if the PSIntuneAuth module needs to be installed - try { - Write-CMLogEntry -Value " - Attempting to locate PSIntuneAuth module" -Severity 1 - $PSIntuneAuthModule = Get-InstalledModule -Name "PSIntuneAuth" -ErrorAction Stop -Verbose:$false - if ($PSIntuneAuthModule -ne $null) { - Write-CMLogEntry -Value " - Authentication module detected, checking for latest version" -Severity 1 - $LatestModuleVersion = (Find-Module -Name "PSIntuneAuth" -ErrorAction SilentlyContinue -Verbose:$false).Version - if ($LatestModuleVersion -gt $PSIntuneAuthModule.Version) { - Write-CMLogEntry -Value " - Latest version of PSIntuneAuth module is not installed, attempting to install: $($LatestModuleVersion.ToString())" -Severity 1 - $UpdateModuleInvocation = Update-Module -Name "PSIntuneAuth" -Scope CurrentUser -Force -ErrorAction Stop -Confirm:$false -Verbose:$false - } - } - } catch [System.Exception] { - Write-CMLogEntry -Value " - Unable to detect PSIntuneAuth module, attempting to install from PSGallery" -Severity 2 - try { - # Install NuGet package provider - $PackageProvider = Install-PackageProvider -Name "NuGet" -Force -Verbose:$false + function Install-AuthModule { + # Determine if the PSIntuneAuth module needs to be installed + try { + Write-CMLogEntry -Value " - Attempting to locate PSIntuneAuth module" -Severity 1 + $PSIntuneAuthModule = Get-InstalledModule -Name "PSIntuneAuth" -ErrorAction Stop -Verbose:$false + if ($PSIntuneAuthModule -ne $null) { + Write-CMLogEntry -Value " - Authentication module detected, checking for latest version" -Severity 1 + $LatestModuleVersion = (Find-Module -Name "PSIntuneAuth" -ErrorAction SilentlyContinue -Verbose:$false).Version + if ($LatestModuleVersion -gt $PSIntuneAuthModule.Version) { + Write-CMLogEntry -Value " - Latest version of PSIntuneAuth module is not installed, attempting to install: $($LatestModuleVersion.ToString())" -Severity 1 + $UpdateModuleInvocation = Update-Module -Name "PSIntuneAuth" -Scope CurrentUser -Force -ErrorAction Stop -Confirm:$false -Verbose:$false + } + } + } + catch [System.Exception] { + Write-CMLogEntry -Value " - Unable to detect PSIntuneAuth module, attempting to install from PSGallery" -Severity 2 + try { + # Install NuGet package provider + $PackageProvider = Install-PackageProvider -Name "NuGet" -Force -Verbose:$false - # Install PSIntuneAuth module - Install-Module -Name "PSIntuneAuth" -Scope AllUsers -Force -ErrorAction Stop -Confirm:$false -Verbose:$false - Write-CMLogEntry -Value " - Successfully installed PSIntuneAuth module" -Severity 1 - } catch [System.Exception] { - Write-CMLogEntry -Value " - An error occurred while attempting to install PSIntuneAuth module. Error message: $($_.Exception.Message)" -Severity 3 + # Install PSIntuneAuth module + Install-Module -Name "PSIntuneAuth" -Scope AllUsers -Force -ErrorAction Stop -Confirm:$false -Verbose:$false + Write-CMLogEntry -Value " - Successfully installed PSIntuneAuth module" -Severity 1 + } + catch [System.Exception] { + Write-CMLogEntry -Value " - An error occurred while attempting to install PSIntuneAuth module. Error message: $($_.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } - function Get-AuthToken { - try { - # Attempt to install PSIntuneAuth module, if already installed ensure the latest version is being used - Install-AuthModule + function Get-AuthToken { + try { + # Attempt to install PSIntuneAuth module, if already installed ensure the latest version is being used + Install-AuthModule - # Import MS Intune Auth Token - Write-CMLogEntry -Value " - Importing PSIntuneAuth PS module" -Severity 1 - Import-Module -Name PSIntuneAuth + # Import MS Intune Auth Token + Write-CMLogEntry -Value " - Importing PSIntuneAuth PS module" -Severity 1 + Import-Module -Name PSIntuneAuth - # Retrieve authentication token - Write-CMLogEntry -Value " - Attempting to retrieve authentication token using native client with ID: $($ClientID)" -Severity 1 - $Script:AuthToken = Get-MSIntuneAuthToken -TenantName $TenantName -ClientID $ClientID -Credential $Credential -Resource $ApplicationIDURI -RedirectUri "https://login.microsoftonline.com/common/oauth2/nativeclient" -ErrorAction Stop - Write-CMLogEntry -Value " - Successfully retrieved authentication token" -Severity 1 - } catch [System.Exception] { - Write-CMLogEntry -Value " - Failed to retrieve authentication token. Error message: $($PSItem.Exception.Message)" -Severity 3 + # Retrieve authentication token + Write-CMLogEntry -Value " - Attempting to retrieve authentication token using native client with ID: $($ClientID)" -Severity 1 + $Script:AuthToken = Get-MSIntuneAuthToken -TenantName $TenantName -ClientID $ClientID -Credential $Credential -Resource $ApplicationIDURI -RedirectUri "https://login.microsoftonline.com/common/oauth2/nativeclient" -ErrorAction Stop + Write-CMLogEntry -Value " - Successfully retrieved authentication token" -Severity 1 + } + catch [System.Exception] { + Write-CMLogEntry -Value " - Failed to retrieve authentication token. Error message: $($PSItem.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } - function Get-AuthCredential { - # Construct PSCredential object for authentication - $EncryptedPassword = ConvertTo-SecureString -String $Script:Password -AsPlainText -Force - $Script:Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($Script:UserName, $EncryptedPassword) - } + function Get-AuthCredential { + # Construct PSCredential object for authentication + $EncryptedPassword = ConvertTo-SecureString -String $Script:Password -AsPlainText -Force + $Script:Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($Script:UserName, $EncryptedPassword) + } - function Get-AdminServiceItem { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the resource for the AdminService API call, e.g. '/SMS_Package'.")] - [ValidateNotNullOrEmpty()] - [string]$Resource - ) - # Construct array object to hold return value - $PackageArray = New-Object -TypeName System.Collections.ArrayList + function Get-AdminServiceItem { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the resource for the AdminService API call, e.g. '/SMS_Package'.")] + [ValidateNotNullOrEmpty()] + [string]$Resource + ) + # Construct array object to hold return value + $PackageArray = New-Object -TypeName System.Collections.ArrayList - switch ($Script:AdminServiceEndpointType) { - "External" { - try { - $AdminServiceUri = $AdminServiceURL + $Resource - Write-CMLogEntry -Value " - Calling AdminService endpoint with URI: $($AdminServiceUri)" -Severity 1 - $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Headers $AuthToken -ErrorAction Stop - } catch [System.Exception] { - Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 + switch ($Script:AdminServiceEndpointType) { + "External" { + try { + $AdminServiceUri = $AdminServiceURL + $Resource + Write-CMLogEntry -Value " - Calling AdminService endpoint with URI: $($AdminServiceUri)" -Severity 1 + $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Headers $AuthToken -ErrorAction Stop + } + catch [System.Exception] { + Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - "Internal" { - $AdminServiceUri = $AdminServiceURL + $Resource - Write-CMLogEntry -Value " - Calling AdminService endpoint with URI: $($AdminServiceUri)" -Severity 1 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + "Internal" { + $AdminServiceUri = $AdminServiceURL + $Resource + Write-CMLogEntry -Value " - Calling AdminService endpoint with URI: $($AdminServiceUri)" -Severity 1 - try { - # Call AdminService endpoint to retrieve package data - $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Credential $Credential -ErrorAction Stop - } catch [System.Security.Authentication.AuthenticationException] { - Write-CMLogEntry -Value " - The remote AdminService endpoint certificate is invalid according to the validation procedure. Error message: $($PSItem.Exception.Message)" -Severity 2 - Write-CMLogEntry -Value " - Will attempt to set the current session to ignore self-signed certificates and retry AdminService endpoint connection" -Severity 2 + try { + # Call AdminService endpoint to retrieve package data + $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Credential $Credential -ErrorAction Stop + } + catch [System.Security.Authentication.AuthenticationException] { + Write-CMLogEntry -Value " - The remote AdminService endpoint certificate is invalid according to the validation procedure. Error message: $($PSItem.Exception.Message)" -Severity 2 + Write-CMLogEntry -Value " - Will attempt to set the current session to ignore self-signed certificates and retry AdminService endpoint connection" -Severity 2 - # Attempt to ignore self-signed certificate binding for AdminService - # Convert encoded base64 string for ignore self-signed certificate validation functionality - $CertificationValidationCallbackEncoded = "DQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0AOwANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB1AHMAaQBuAGcAIABTAHkAcwB0AGUAbQAuAE4AZQB0ADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQBjAHUAcgBpAHQAeQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AUwBlAGMAdQByAGkAdAB5AC4AQwByAHkAcAB0AG8AZwByAGEAcABoAHkALgBYADUAMAA5AEMAZQByAHQAaQBmAGkAYwBhAHQAZQBzADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAcAB1AGIAbABpAGMAIABjAGwAYQBzAHMAIABTAGUAcgB2AGUAcgBDAGUAcgB0AGkAZgBpAGMAYQB0AGUAVgBhAGwAaQBkAGEAdABpAG8AbgBDAGEAbABsAGIAYQBjAGsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIAB2AG8AaQBkACAASQBnAG4AbwByAGUAKAApAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAaQBmACgAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgAD0APQBuAHUAbABsACkADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgACsAPQAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAZABlAGwAZQBnAGEAdABlAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAATwBiAGoAZQBjAHQAIABvAGIAagAsACAADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAFgANQAwADkAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBlAHIAdABpAGYAaQBjAGEAdABlACwAIAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAWAA1ADAAOQBDAGgAYQBpAG4AIABjAGgAYQBpAG4ALAAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIABTAHMAbABQAG8AbABpAGMAeQBFAHIAcgBvAHIAcwAgAGUAcgByAG8AcgBzAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHIAZQB0AHUAcgBuACAAdAByAHUAZQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAA" - $CertificationValidationCallback = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($CertificationValidationCallbackEncoded)) + # Attempt to ignore self-signed certificate binding for AdminService + # Convert encoded base64 string for ignore self-signed certificate validation functionality + $CertificationValidationCallbackEncoded = "DQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0AOwANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB1AHMAaQBuAGcAIABTAHkAcwB0AGUAbQAuAE4AZQB0ADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAdQBzAGkAbgBnACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQBjAHUAcgBpAHQAeQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHUAcwBpAG4AZwAgAFMAeQBzAHQAZQBtAC4AUwBlAGMAdQByAGkAdAB5AC4AQwByAHkAcAB0AG8AZwByAGEAcABoAHkALgBYADUAMAA5AEMAZQByAHQAaQBmAGkAYwBhAHQAZQBzADsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAcAB1AGIAbABpAGMAIABjAGwAYQBzAHMAIABTAGUAcgB2AGUAcgBDAGUAcgB0AGkAZgBpAGMAYQB0AGUAVgBhAGwAaQBkAGEAdABpAG8AbgBDAGEAbABsAGIAYQBjAGsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIAB2AG8AaQBkACAASQBnAG4AbwByAGUAKAApAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAewANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAaQBmACgAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgAD0APQBuAHUAbABsACkADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAUwBlAHIAdgBpAGMAZQBQAG8AaQBuAHQATQBhAG4AYQBnAGUAcgAuAFMAZQByAHYAZQByAEMAZQByAHQAaQBmAGkAYwBhAHQAZQBWAGEAbABpAGQAYQB0AGkAbwBuAEMAYQBsAGwAYgBhAGMAawAgACsAPQAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAZABlAGwAZQBnAGEAdABlAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAATwBiAGoAZQBjAHQAIABvAGIAagAsACAADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAFgANQAwADkAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBlAHIAdABpAGYAaQBjAGEAdABlACwAIAANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAWAA1ADAAOQBDAGgAYQBpAG4AIABjAGgAYQBpAG4ALAAgAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIABTAHMAbABQAG8AbABpAGMAeQBFAHIAcgBvAHIAcwAgAGUAcgByAG8AcgBzAA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAKQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHsADQAKACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgAHIAZQB0AHUAcgBuACAAdAByAHUAZQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQA7AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAfQANAAoAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAB9AA0ACgAgACAAIAAgACAAIAAgACAA" + $CertificationValidationCallback = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($CertificationValidationCallbackEncoded)) - # Load required type definition to be able to ignore self-signed certificate to circumvent issues with AdminService running with ConfigMgr self-signed certificate binding - Add-Type -TypeDefinition $CertificationValidationCallback - [ServerCertificateValidationCallback]::Ignore() + # Load required type definition to be able to ignore self-signed certificate to circumvent issues with AdminService running with ConfigMgr self-signed certificate binding + Add-Type -TypeDefinition $CertificationValidationCallback + [ServerCertificateValidationCallback]::Ignore() - try { - # Call AdminService endpoint to retrieve package data - $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Credential $Credential -ErrorAction Stop - } catch [System.Exception] { - Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 + try { + # Call AdminService endpoint to retrieve package data + $AdminServiceResponse = Invoke-RestMethod -Method Get -Uri $AdminServiceUri -Credential $Credential -ErrorAction Stop + } + catch [System.Exception] { + Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } catch { - Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + catch { + Write-CMLogEntry -Value " - Failed to retrieve available package items from AdminService endpoint. Error message: $($PSItem.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } - # Add returned driver package objects to array list - if ($AdminServiceResponse.value -ne $null) { - foreach ($Package in $AdminServiceResponse.value) { - $PackageArray.Add($Package) | Out-Null - } - } + # Add returned driver package objects to array list + if ($AdminServiceResponse.value -ne $null) { + foreach ($Package in $AdminServiceResponse.value) { + $PackageArray.Add($Package) | Out-Null + } + } - # Handle return value - return $PackageArray - } + # Handle return value + return $PackageArray + } - function Get-BIOSPackages { - try { - # Retrieve BIOS packages but filter out matches depending on script operational mode - switch ($OperationalMode) { - "Production" { - if ($Script:PSCmdlet.ParameterSetName -like "XMLPackage") { - Write-CMLogEntry -Value " - Reading XML content logic file BIOS package entries" -Severity 1 - $Packages = (([xml]$(Get-Content -Path $XMLPackageLogicFile -Raw)).ArrayOfCMPackage).CMPackage | Where-Object { - $_.Name -notmatch "Pilot" -and $_.Name -notmatch "Legacy" -and $_.Name -match $Filter - } - } else { - Write-CMLogEntry -Value " - Querying AdminService for BIOS package instances" -Severity 1 - $Packages = Get-AdminServiceItem -Resource "/SMS_Package?`$filter=contains(Name,'$($Filter)')" | Where-Object { - $_.Name -notmatch "Pilot" -and $_.Name -notmatch "Retired" - } - } + function Get-BIOSPackages { + try { + # Retrieve BIOS packages but filter out matches depending on script operational mode + switch ($OperationalMode) { + "Production" { + if ($Script:PSCmdlet.ParameterSetName -like "XMLPackage") { + Write-CMLogEntry -Value " - Reading XML content logic file BIOS package entries" -Severity 1 + $Packages = (([xml]$(Get-Content -Path $XMLPackageLogicFile -Raw)).ArrayOfCMPackage).CMPackage | Where-Object { + $_.Name -notmatch "Pilot" -and $_.Name -notmatch "Legacy" -and $_.Name -match $Filter + } + } + else { + Write-CMLogEntry -Value " - Querying AdminService for BIOS package instances" -Severity 1 + $Packages = Get-AdminServiceItem -Resource "/SMS_Package?`$filter=contains(Name,'$($Filter)')" | Where-Object { + $_.Name -notmatch "Pilot" -and $_.Name -notmatch "Retired" + } + } - } - "Pilot" { - if ($Script:PSCmdlet.ParameterSetName -like "XMLPackage") { - Write-CMLogEntry -Value " - Reading XML content logic file BIOS package entries" -Severity 1 - $Packages = (([xml]$(Get-Content -Path $XMLPackageLogicFile -Raw)).ArrayOfCMPackage).CMPackage | Where-Object { - $_.Name -match "Pilot" -and $_.Name -match $Filter - } - } else { - Write-CMLogEntry -Value " - Querying AdminService for BIOS package instances" -Severity 1 - $Packages = Get-AdminServiceItem -Resource "/SMS_Package?`$filter=contains(Name,'$($Filter)')" | Where-Object { - $_.Name -match "Pilot" - } - } - } - } + } + "Pilot" { + if ($Script:PSCmdlet.ParameterSetName -like "XMLPackage") { + Write-CMLogEntry -Value " - Reading XML content logic file BIOS package entries" -Severity 1 + $Packages = (([xml]$(Get-Content -Path $XMLPackageLogicFile -Raw)).ArrayOfCMPackage).CMPackage | Where-Object { + $_.Name -match "Pilot" -and $_.Name -match $Filter + } + } + else { + Write-CMLogEntry -Value " - Querying AdminService for BIOS package instances" -Severity 1 + $Packages = Get-AdminServiceItem -Resource "/SMS_Package?`$filter=contains(Name,'$($Filter)')" | Where-Object { + $_.Name -match "Pilot" + } + } + } + } - # Handle return value - if ($Packages -ne $null) { - Write-CMLogEntry -Value " - Retrieved a total of '$(($Packages | Measure-Object).Count)' BIOS packages from $($Script:PackageSource) matching operational mode: $($OperationalMode)" -Severity 1 - return $Packages - } else { - Write-CMLogEntry -Value " - Retrieved a total of '0' BIOS packages from $($Script:PackageSource) matching operational mode: $($OperationalMode)" -Severity 3 + # Handle return value + if ($Packages -ne $null) { + Write-CMLogEntry -Value " - Retrieved a total of '$(($Packages | Measure-Object).Count)' BIOS packages from $($Script:PackageSource) matching operational mode: $($OperationalMode)" -Severity 1 + return $Packages + } + else { + Write-CMLogEntry -Value " - Retrieved a total of '0' BIOS packages from $($Script:PackageSource) matching operational mode: $($OperationalMode)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } catch [System.Exception] { - Write-CMLogEntry -Value " - An error occurred while calling $($Script:PackageSource) for a list of available BIOS packages. Error message: $($_.Exception.Message)" -Severity 3 + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + catch [System.Exception] { + Write-CMLogEntry -Value " - An error occurred while calling $($Script:PackageSource) for a list of available BIOS packages. Error message: $($_.Exception.Message)" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } - function Get-ComputerData { - # Create a custom object for computer details gathered from local WMI - $ComputerDetails = [PSCustomObject]@{ - Manufacturer = $null - Model = $null - SystemSKU = $null - FallbackSKU = $null - } + function Get-ComputerData { + # Create a custom object for computer details gathered from local WMI + $ComputerDetails = [PSCustomObject]@{ + Manufacturer = $null + Model = $null + SystemSKU = $null + FallbackSKU = $null + } - # Gather computer details based upon specific computer manufacturer - $ComputerManufacturer = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Manufacturer).Trim() - switch -Wildcard ($ComputerManufacturer) { - "*Microsoft*" { - $ComputerDetails.Manufacturer = "Microsoft" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = Get-WmiObject -Namespace "root\wmi" -Class "MS_SystemInformation" | Select-Object -ExpandProperty SystemSKU - } - "*HP*" { - $ComputerDetails.Manufacturer = "HP" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim() - } - "*Hewlett-Packard*" { - $ComputerDetails.Manufacturer = "HP" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim() - } - "*Dell*" { - $ComputerDetails.Manufacturer = "Dell" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").SystemSku.Trim() - [string]$OEMString = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty OEMStringArray - $ComputerDetails.FallbackSKU = [regex]::Matches($OEMString, '\[\S*]')[0].Value.TrimStart("[").TrimEnd("]") - } - "*Lenovo*" { - $ComputerDetails.Manufacturer = "Lenovo" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystemProduct" | Select-Object -ExpandProperty Version).Trim() - $ComputerDetails.SystemSKU = ((Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).SubString(0, 4)).Trim() - } - "*Panasonic*" { - $ComputerDetails.Manufacturer = "Panasonic Corporation" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace "root\WMI").BaseBoardProduct.Trim() - } - "*Viglen*" { - $ComputerDetails.Manufacturer = "Viglen" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim() - } - "*AZW*" { - $ComputerDetails.Manufacturer = "AZW" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-CIMInstance -ClassName "MS_SystemInformation" -NameSpace root\WMI).BaseBoardProduct.Trim() - } - "*Fujitsu*" { - $ComputerDetails.Manufacturer = "Fujitsu" - $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim() - } - } + # Gather computer details based upon specific computer manufacturer + $ComputerManufacturer = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Manufacturer).Trim() + switch -Wildcard ($ComputerManufacturer) { + "*Microsoft*" { + $ComputerDetails.Manufacturer = "Microsoft" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = Get-WmiObject -Namespace "root\wmi" -Class "MS_SystemInformation" | Select-Object -ExpandProperty SystemSKU + } + "*HP*" { + $ComputerDetails.Manufacturer = "HP" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace "root\WMI").BaseBoardProduct.Trim() + } + "*Hewlett-Packard*" { + $ComputerDetails.Manufacturer = "HP" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace "root\WMI").BaseBoardProduct.Trim() + } + "*Dell*" { + $ComputerDetails.Manufacturer = "Dell" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace "root\WMI").SystemSku.Trim() + [string]$OEMString = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty OEMStringArray + $ComputerDetails.FallbackSKU = [regex]::Matches($OEMString, '\[\S*]')[0].Value.TrimStart("[").TrimEnd("]") + } + "*Lenovo*" { + $ComputerDetails.Manufacturer = "Lenovo" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystemProduct" | Select-Object -ExpandProperty Version).Trim() + $ComputerDetails.SystemSKU = ((Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).SubString(0, 4)).Trim() + } + "*Panasonic*" { + $ComputerDetails.Manufacturer = "Panasonic Corporation" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace "root\WMI").BaseBoardProduct.Trim() + } + "*Viglen*" { + $ComputerDetails.Manufacturer = "Viglen" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim() + } + "*AZW*" { + $ComputerDetails.Manufacturer = "AZW" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace root\WMI).BaseBoardProduct.Trim() + } + "*Fujitsu*" { + $ComputerDetails.Manufacturer = "Fujitsu" + $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() + $ComputerDetails.SystemSKU = (Get-WmiObject -Class "Win32_BaseBoard" | Select-Object -ExpandProperty SKU).Trim() + } + } - # Handle overriding computer details if debug mode and additional parameters was specified - if ($Script:PSCmdlet.ParameterSetName -like "Debug") { - if (-not ([string]::IsNullOrEmpty($Manufacturer))) { - $ComputerDetails.Manufacturer = $Manufacturer - } - if (-not ([string]::IsNullOrEmpty($ComputerModel))) { - $ComputerDetails.Model = $ComputerModel - } - if (-not ([string]::IsNullOrEmpty($SystemSKU))) { - $ComputerDetails.SystemSKU = $SystemSKU - } - } + # Handle overriding computer details if debug mode and additional parameters was specified + if ($Script:PSCmdlet.ParameterSetName -like "Debug") { + if (-not ([string]::IsNullOrEmpty($Manufacturer))) { + $ComputerDetails.Manufacturer = $Manufacturer + } + if (-not ([string]::IsNullOrEmpty($ComputerModel))) { + $ComputerDetails.Model = $ComputerModel + } + if (-not ([string]::IsNullOrEmpty($SystemSKU))) { + $ComputerDetails.SystemSKU = $SystemSKU + } + } - # Handle output to log file for computer details - Write-CMLogEntry -Value " - Computer manufacturer determined as: $($ComputerDetails.Manufacturer)" -Severity 1 - Write-CMLogEntry -Value " - Computer model determined as: $($ComputerDetails.Model)" -Severity 1 + # Handle output to log file for computer details + Write-CMLogEntry -Value " - Computer manufacturer determined as: $($ComputerDetails.Manufacturer)" -Severity 1 + Write-CMLogEntry -Value " - Computer model determined as: $($ComputerDetails.Model)" -Severity 1 - # Handle output to log file for computer SystemSKU - if (-not ([string]::IsNullOrEmpty($ComputerDetails.SystemSKU))) { - Write-CMLogEntry -Value " - Computer SystemSKU determined as: $($ComputerDetails.SystemSKU)" -Severity 1 - } else { - Write-CMLogEntry -Value " - Computer SystemSKU determined as: " -Severity 2 - } + # Handle output to log file for computer SystemSKU + if (-not ([string]::IsNullOrEmpty($ComputerDetails.SystemSKU))) { + Write-CMLogEntry -Value " - Computer SystemSKU determined as: $($ComputerDetails.SystemSKU)" -Severity 1 + } + else { + Write-CMLogEntry -Value " - Computer SystemSKU determined as: " -Severity 2 + if (-not ([string]::IsNullOrEmpty($ComputerDetails.FallBackSKU))) { + Write-CMLogEntry -Value " - Replacing Null SystemSKU with Fallback SystemSKU: $($ComputerDetails.FallBackSKU)" -Severity 1 + $ComputerDetails.SystemSKU = $ComputerDetails.FallbackSKU + } + } - # Handle output to log file for Fallback SKU - if (-not ([string]::IsNullOrEmpty($ComputerDetails.FallBackSKU))) { - Write-CMLogEntry -Value " - Computer Fallback SystemSKU determined as: $($ComputerDetails.FallBackSKU)" -Severity 1 - } + # Handle output to log file for Fallback SKU + if (-not ([string]::IsNullOrEmpty($ComputerDetails.FallBackSKU))) { + Write-CMLogEntry -Value " - Computer Fallback SystemSKU determined as: $($ComputerDetails.FallBackSKU)" -Severity 1 + } - # Handle return value from function - return $ComputerDetails - } + # Handle return value from function + return $ComputerDetails + } - function Get-ComputerSystemType { - $ComputerSystemType = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty "Model" - if ($ComputerSystemType -notin @("Virtual Machine", "VMware Virtual Platform", "VirtualBox", "HVM domU", "KVM", "VMWare7,1")) { - Write-CMLogEntry -Value " - Supported computer platform detected, script execution allowed to continue" -Severity 1 - } else { - if ($Script:PSCmdlet.ParameterSetName -like "Debug") { - Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported but will be allowed in DebugMode" -Severity 2 - } else { - Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported" -Severity 3 + function Get-ComputerSystemType { + $ComputerSystemType = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty "Model" + if ($ComputerSystemType -notin @("Virtual Machine", "VMware Virtual Platform", "VirtualBox", "HVM domU", "KVM", "VMWare7,1")) { + Write-CMLogEntry -Value " - Supported computer platform detected, script execution allowed to continue" -Severity 1 + } + else { + if ($Script:PSCmdlet.ParameterSetName -like "Debug") { + Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported but will be allowed in DebugMode" -Severity 2 + } + else { + Write-CMLogEntry -Value " - Unsupported computer platform detected, virtual machines are not supported" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + } + } - function Test-ComputerDetails { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")] - [ValidateNotNullOrEmpty()] - [PSCustomObject]$InputObject - ) - # Construct custom object for computer details validation - $Script:ComputerDetection = [PSCustomObject]@{ - "ModelDetected" = $false - "SystemSKUDetected" = $false - } + function Test-ComputerDetails { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")] + [ValidateNotNullOrEmpty()] + [PSCustomObject]$InputObject + ) + # Construct custom object for computer details validation + $Script:ComputerDetection = [PSCustomObject]@{ + "ModelDetected" = $false + "SystemSKUDetected" = $false + } - if (($InputObject.Model -ne $null) -and (-not ([System.String]::IsNullOrEmpty($InputObject.Model)))) { - Write-CMLogEntry -Value " - Computer model detection was successful" -Severity 1 - $ComputerDetection.ModelDetected = $true - } + if (($InputObject.Model -ne $null) -and (-not ([System.String]::IsNullOrEmpty($InputObject.Model)))) { + Write-CMLogEntry -Value " - Computer model detection was successful" -Severity 1 + $ComputerDetection.ModelDetected = $true + } - if (($InputObject.SystemSKU -ne $null) -and (-not ([System.String]::IsNullOrEmpty($InputObject.SystemSKU)))) { - Write-CMLogEntry -Value " - Computer SystemSKU detection was successful" -Severity 1 - $ComputerDetection.SystemSKUDetected = $true - } + if (($InputObject.SystemSKU -ne $null) -and (-not ([System.String]::IsNullOrEmpty($InputObject.SystemSKU)))) { + Write-CMLogEntry -Value " - Computer SystemSKU detection was successful" -Severity 1 + $ComputerDetection.SystemSKUDetected = $true + } - if (($ComputerDetection.ModelDetected -eq $false) -and ($ComputerDetection.SystemSKUDetected -eq $false)) { - Write-CMLogEntry -Value " - Computer model and SystemSKU values are missing, script execution is not allowed since required values to continue could not be gathered" -Severity 3 + if (($ComputerDetection.ModelDetected -eq $false) -and ($ComputerDetection.SystemSKUDetected -eq $false)) { + Write-CMLogEntry -Value " - Computer model and SystemSKU values are missing, script execution is not allowed since required values to continue could not be gathered" -Severity 3 - # Throw terminating error - $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) - $PSCmdlet.ThrowTerminatingError($ErrorRecord) - } else { - Write-CMLogEntry -Value " - Computer details successfully verified" -Severity 1 - } - } + # Throw terminating error + $ErrorRecord = New-TerminatingErrorRecord -Message ([string]::Empty) + $PSCmdlet.ThrowTerminatingError($ErrorRecord) + } + else { + Write-CMLogEntry -Value " - Computer details successfully verified" -Severity 1 + } + } - function Set-ComputerDetectionMethod { - if ($ComputerDetection.SystemSKUDetected -eq $true) { - Write-CMLogEntry -Value " - Determined primary computer detection method: SystemSKU" -Severity 1 - return "SystemSKU" - } else { - Write-CMLogEntry -Value " - Determined fallback computer detection method: ComputerModel" -Severity 1 - return "ComputerModel" - } - } + function Set-ComputerDetectionMethod { + if ($ComputerDetection.SystemSKUDetected -eq $true) { + Write-CMLogEntry -Value " - Determined primary computer detection method: SystemSKU" -Severity 1 + return "SystemSKU" + } + else { + Write-CMLogEntry -Value " - Determined fallback computer detection method: ComputerModel" -Severity 1 + return "ComputerModel" + } + } - function Compare-BIOSVersion { - param ( - [parameter(Mandatory = $false, HelpMessage = "Current available BIOS version.")] - [ValidateNotNullOrEmpty()] - [string]$AvailableBIOSVersion, - [parameter(Mandatory = $false, HelpMessage = "Current available BIOS revision date.")] - [string]$AvailableBIOSReleaseDate, - [parameter(Mandatory = $true, HelpMessage = "Current available BIOS version.")] - [ValidateNotNullOrEmpty()] - [string]$ComputerManufacturer - ) + function Compare-BIOSVersion { + param ( + [parameter(Mandatory = $false, HelpMessage = "Current available BIOS version.")] + [ValidateNotNullOrEmpty()] + [string]$AvailableBIOSVersion, + [parameter(Mandatory = $false, HelpMessage = "Current available BIOS revision date.")] + [string]$AvailableBIOSReleaseDate, + [parameter(Mandatory = $true, HelpMessage = "Current available BIOS version.")] + [ValidateNotNullOrEmpty()] + [string]$ComputerManufacturer + ) - if ($ComputerManufacturer -match "Dell") { - # Obtain current BIOS release - $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() - Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release deteced as $($AvailableBIOSVersion)." -Severity 1 + if ($ComputerManufacturer -match "Dell") { + # Obtain current BIOS release + $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() + Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release deteced as $($AvailableBIOSVersion)." -Severity 1 - # Determine Dell BIOS revision format - if ($CurrentBIOSVersion -like "*.*.*") { - # Compare current BIOS release to available - if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } elseif ($CurrentBIOSVersion -like "A*") { - # Compare current BIOS release to available - if ($AvailableBIOSVersion -like "*.*.*") { - # Assume that the bios is new as moving from Axx to x.x.x formats - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } elseif ($AvailableBIOSVersion -gt $CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - } + # Determine Dell BIOS revision format + if ($CurrentBIOSVersion -like "*.*.*") { + # Compare current BIOS release to available + if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + elseif ($CurrentBIOSVersion -like "A*") { + # Compare current BIOS release to available + if ($AvailableBIOSVersion -like "*.*.*") { + # Assume that the bios is new as moving from Axx to x.x.x formats + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + elseif ($AvailableBIOSVersion -gt $CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + } - if ($ComputerManufacturer -match "Lenovo") { - # Obtain current BIOS release - $CurrentBIOSReleaseDate = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) - Write-CMLogEntry -Value "Current BIOS release date detected as $($CurrentBIOSReleaseDate)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release date detected as $($AvailableBIOSReleaseDate)." -Severity 1 + if ($ComputerManufacturer -match "Lenovo") { + # Obtain current BIOS release + $CurrentBIOSReleaseDate = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) + Write-CMLogEntry -Value "Current BIOS release date detected as $($CurrentBIOSReleaseDate)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release date detected as $($AvailableBIOSReleaseDate)." -Severity 1 - # Compare current BIOS release to available - if ($AvailableBIOSReleaseDate -gt $CurrentBIOSReleaseDate) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current date release dated $($CurrentBIOSReleaseDate) will be replaced by release $($AvailableBIOSReleaseDate)." -Severity 1 - } - } + # Compare current BIOS release to available + if ($AvailableBIOSReleaseDate -gt $CurrentBIOSReleaseDate) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current date release dated $($CurrentBIOSReleaseDate) will be replaced by release $($AvailableBIOSReleaseDate)." -Severity 1 + } + } - if ($ComputerManufacturer -match "Hewlett-Packard|HP") { - # Obtain current BIOS release - $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) + if ($ComputerManufacturer -match "Hewlett-Packard|HP") { + # Obtain current BIOS release + $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) - # Update version formatting - $AvailableBIOSVersion = $AvailableBIOSVersion.TrimEnd(".") - $AvailableBIOSVersion = $AvailableBIOSVersion.Split(" ")[0] + # Update version formatting + $AvailableBIOSVersion = $AvailableBIOSVersion.TrimEnd(".") + $AvailableBIOSVersion = $AvailableBIOSVersion.Split(" ")[0] - # Detect new versus old BIOS formats - switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { - "*ver*" { - if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { - $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() - $BIOSVersionParseable = $false - } else { - $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) - $BIOSVersionParseable = $true - } - } - default { - $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" - $BIOSVersionParseable = $true - } - } + # Detect new versus old BIOS formats + switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { + "*ver*" { + if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { + $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() + $BIOSVersionParseable = $false + } + else { + $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) + $BIOSVersionParseable = $true + } + } + default { + $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" + $BIOSVersionParseable = $true + } + } - # Output version details - Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release detected as $($AvailableBIOSVersion)." -Severity 1 + # Output version details + Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 + Write-CMLogEntry -Value "Available BIOS release detected as $($AvailableBIOSVersion)." -Severity 1 - # Compare current BIOS release to available - switch ($BIOSVersionParseable) { - $true { - if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - $false { - if ([System.Int32]::Parse($AvailableBIOSVersion.TrimStart("F.")) -gt [System.Int32]::Parse($CurrentBIOSVersion.TrimStart("F."))) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - } - } - } + # Compare current BIOS release to available + switch ($BIOSVersionParseable) { + $true { + if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + $false { + if ([System.Int32]::Parse($AvailableBIOSVersion.TrimStart("F.")) -gt [System.Int32]::Parse($CurrentBIOSVersion.TrimStart("F."))) { + # Write output to task sequence variable + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + $TSEnvironment.Value("NewBIOSAvailable") = $true + } + Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 + } + } + } + } + } - function Get-BIOSUpdate { - param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")] - [ValidateNotNullOrEmpty()] - [PSCustomObject]$InputObject - ) + function Get-BIOSUpdate { + param ( + [parameter(Mandatory = $true, HelpMessage = "Specify the computer details object from Get-ComputerDetails function.")] + [ValidateNotNullOrEmpty()] + [PSCustomObject]$InputObject + ) - # Define machine matching values - $ComputerSystemType = $InputObject.Model - $ComputerManufacturer = $InputObject.Manufacturer - $SystemSKU = $InputObject.SystemSKU + # Define machine matching values + $ComputerSystemType = $InputObject.Model + $ComputerManufacturer = $InputObject.Manufacturer + $SystemSKU = $InputObject.SystemSKU - # Supported manufacturers - $Manufacturers = @("Dell", "Hewlett-Packard", "Lenovo", "Microsoft", "HP") + # Supported manufacturers + $Manufacturers = @("Dell", "Hewlett-Packard", "Lenovo", "Microsoft", "HP") - $PackageList = New-Object -TypeName System.Collections.ArrayList + $PackageList = New-Object -TypeName System.Collections.ArrayList - if ($ComputerSystemType -notin @("Virtual Machine", "VMware Virtual Platform", "VirtualBox", "HVM domU", "KVM")) { - # Process packages returned from web service - if ($BIOSPackages -ne $null) { - if (($ComputerModel -ne $null) -and (-not ([System.String]::IsNullOrEmpty($ComputerModel))) -or (($SystemSKU -ne $null) -and (-not ([System.String]::IsNullOrEmpty($SystemSKU))))) { - # Determine computer model detection - if ([System.String]::IsNullOrEmpty($SystemSKU)) { - Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.PackageName) ($($Package.PackageID))" -Severity 1 - Write-CMLogEntry -Value "Computer detection method set to use ComptuerModel" -Severity 1 - $ComputerDetectionMethod = "ComputerModel" - } else { - Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.PackageName) ($($Package.PackageID))" -Severity 1 - Write-CMLogEntry -Value "Computer detection method set to use SystemSKU" -Severity 1 - $ComputerDetectionMethod = "SystemSKU" - } + if ($ComputerSystemType -notin @("Virtual Machine", "VMware Virtual Platform", "VirtualBox", "HVM domU", "KVM")) { + # Process packages returned from web service + if ($BIOSPackages -ne $null) { + if (($ComputerModel -ne $null) -and (-not ([System.String]::IsNullOrEmpty($ComputerModel))) -or (($SystemSKU -ne $null) -and (-not ([System.String]::IsNullOrEmpty($SystemSKU))))) { + # Determine computer model detection + if ([System.String]::IsNullOrEmpty($SystemSKU)) { + Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.PackageName) ($($Package.PackageID))" -Severity 1 + Write-CMLogEntry -Value "Computer detection method set to use ComptuerModel" -Severity 1 + $ComputerDetectionMethod = "ComputerModel" + } + else { + Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.PackageName) ($($Package.PackageID))" -Severity 1 + Write-CMLogEntry -Value "Computer detection method set to use SystemSKU" -Severity 1 + $ComputerDetectionMethod = "SystemSKU" + } - # Add packages with matching criteria to list - foreach ($Package in $BIOSPackages) { - Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.Name) ($($Package.PackageID)) $($Package.Version)" -Severity 1 + # Add packages with matching criteria to list + foreach ($Package in $BIOSPackages) { + Write-CMLogEntry -Value "Attempting to find a match for BIOS package: $($Package.Name) ($($Package.PackageID)) $($Package.Version)" -Severity 1 - # Computer detection method matching - $ComputerDetectionResult = $false - switch ($ComputerManufacturer) { - "Hewlett-Packard" { - $PackageNameComputerModel = $Package.Name.Replace("Hewlett-Packard", "HP").Split("-").Trim()[1] - } - Default { - $PackageNameComputerModel = $Package.Name.Split("-", 2).Replace($ComputerManufacturer, "").Trim()[1] - } - } + # Computer detection method matching + $ComputerDetectionResult = $false + switch ($ComputerManufacturer) { + "Hewlett-Packard" { + $PackageNameComputerModel = $Package.Name.Replace("Hewlett-Packard", "HP").Split("-").Trim()[1] + } + Default { + $PackageNameComputerModel = $Package.Name.Split("-", 2).Replace($ComputerManufacturer, "").Trim()[1] + } + } - switch ($ComputerDetectionMethod) { - "ComputerModel" { - if ($PackageNameComputerModel -like $ComputerModel) { - Write-CMLogEntry -Value "Match found for computer model using detection method: $($ComputerDetectionMethod) ($($ComputerModel))" -Severity 1 - $ComputerDetectionResult = $true - } - } - "SystemSKU" { - if ($Package.Description -match $SystemSKU) { - Write-CMLogEntry -Value "Match found for computer model using detection method: $($ComputerDetectionMethod) ($($SystemSKU))" -Severity 1 - $ComputerDetectionResult = $true - } else { - Write-CMLogEntry -Value "Unable to match computer model using detection method: $($ComputerDetectionMethod) ($($SystemSKU))" -Severity 2 - if ($PackageNameComputerModel -like $ComputerModel) { - Write-CMLogEntry -Value "Fallback from SystemSKU match found for computer model instead using detection method: $($ComputerDetectionMethod) ($($ComputerModel))" -Severity 1 - $ComputerDetectionResult = $true - } - } - } - } + switch ($ComputerDetectionMethod) { + "ComputerModel" { + if ($PackageNameComputerModel -like $ComputerModel) { + Write-CMLogEntry -Value "Match found for computer model using detection method: $($ComputerDetectionMethod) ($($ComputerModel))" -Severity 1 + $ComputerDetectionResult = $true + } + } + "SystemSKU" { + if ($Package.Description -match $SystemSKU) { + Write-CMLogEntry -Value "Match found for computer model using detection method: $($ComputerDetectionMethod) ($($SystemSKU))" -Severity 1 + $ComputerDetectionResult = $true + } + else { + Write-CMLogEntry -Value "Unable to match computer model using detection method: $($ComputerDetectionMethod) ($($SystemSKU))" -Severity 2 + if ($PackageNameComputerModel -like $ComputerModel) { + Write-CMLogEntry -Value "Fallback from SystemSKU match found for computer model instead using detection method: $($ComputerDetectionMethod) ($($ComputerModel))" -Severity 1 + $ComputerDetectionResult = $true + } + } + } + } - if ($ComputerDetectionResult -eq $true) { - # Match model, manufacturer criteria - if ($Manufacturers -contains $ComputerManufacturer) { - if ($ComputerManufacturer -match $Package.Manufacturer) { - Write-CMLogEntry -Value "Match found for computer model and manufacturer: $($Package.Name) ($($Package.PackageID))" -Severity 1 - $PackageList.Add($Package) | Out-Null - } else { - Write-CMLogEntry -Value "Package does not meet computer model and manufacturer criteria: $($Package.PackageName) ($($Package.PackageID))" -Severity 2 - } - } - } + if ($ComputerDetectionResult -eq $true) { + # Match model, manufacturer criteria + if ($Manufacturers -contains $ComputerManufacturer) { + if ($ComputerManufacturer -match $Package.Manufacturer) { + Write-CMLogEntry -Value "Match found for computer model and manufacturer: $($Package.Name) ($($Package.PackageID))" -Severity 1 + $PackageList.Add($Package) | Out-Null + } + else { + Write-CMLogEntry -Value "Package does not meet computer model and manufacturer criteria: $($Package.PackageName) ($($Package.PackageID))" -Severity 2 + } + } + } - } + } - # Process matching items in package list and set task sequence variable - if ($PackageList.Count -ge 1) { - Write-CMLogEntry -Value "[BIOSValidation]: Starting BIOS package validation phase" -Severity 1 - # Determine the most current package from list - if ($PackageList.Count -eq 1) { - Write-CMLogEntry -Value "BIOS package list contains a single match, attempting to set task sequence variable" -Severity 1 + # Process matching items in package list and set task sequence variable + if ($PackageList.Count -ge 1) { + Write-CMLogEntry -Value "[BIOSValidation]: Starting BIOS package validation phase" -Severity 1 + # Determine the most current package from list + if ($PackageList.Count -eq 1) { + Write-CMLogEntry -Value "BIOS package list contains a single match, attempting to set task sequence variable" -Severity 1 - # Check if BIOS package is newer than currently installed - if ($ComputerManufacturer -match "Dell") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Lenovo") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].Description).Split(":")[2].Trimend(")")) -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Microsoft") { - $NewBIOSAvailable = $true - } + # Check if BIOS package is newer than currently installed + if ($ComputerManufacturer -match "Dell") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Lenovo") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].Description).Split(":")[2].Trimend(")")) -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Microsoft") { + $NewBIOSAvailable = $true + } - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - if ($TSEnvironment.Value("NewBIOSAvailable") -eq $true) { - # Attempt to download BIOS package content - $DownloadInvocation = Invoke-CMDownloadContent -PackageID $($PackageList[0].PackageID) -DestinationLocationType Custom -DestinationVariableName "OSDBIOSPackage" -CustomLocationPath "%_SMSTSMDataPath%\BIOSPackage" - try { - # Check for successful package download - if ($DownloadInvocation -eq 0) { - Write-CMLogEntry -Value "BIOS update package content downloaded successfully. Update located in: $($TSEnvironment.Value('OSDBIOSPackage01'))" -Severity 1 - Write-CMLogEntry -Value "[BIOSPackageDownload]: Completed BIOS package download phase" -Severity 1 - } else { - Write-CMLogEntry -Value "BIOS update package content download process returned an unhandled exit code: $($DownloadInvocation)" -Severity 3; exit 13 - } - } catch [System.Exception] { - Write-CMLogEntry -Value "An error occurred while downloading the BIOS update (single package match). Error message: $($_.Exception.Message)" -Severity 3; exit 14 - } - } else { - Write-CMLogEntry -Value "BIOS is already up to date with the latest $($PackageList[0].PackageVersion) version" -Severity 1 - } - } else { - Write-CMLogEntry -Value "Task sequence engine would have been instructed to download package ID $($PackageList[0].PackageID) to %_SMSTSMDataPath%\BIOSPackage" -Severity 1 - } + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + if ($TSEnvironment.Value("NewBIOSAvailable") -eq $true) { + # Attempt to download BIOS package content + $DownloadInvocation = Invoke-CMDownloadContent -PackageID $($PackageList[0].PackageID) -DestinationLocationType Custom -DestinationVariableName "OSDBIOSPackage" -CustomLocationPath "%_SMSTSMDataPath%\BIOSPackage" + try { + # Check for successful package download + if ($DownloadInvocation -eq 0) { + Write-CMLogEntry -Value "BIOS update package content downloaded successfully. Update located in: $($TSEnvironment.Value('OSDBIOSPackage01'))" -Severity 1 + Write-CMLogEntry -Value "[BIOSPackageDownload]: Completed BIOS package download phase" -Severity 1 + } + else { + Write-CMLogEntry -Value "BIOS update package content download process returned an unhandled exit code: $($DownloadInvocation)" -Severity 3; exit 13 + } + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occurred while downloading the BIOS update (single package match). Error message: $($_.Exception.Message)" -Severity 3; exit 14 + } + } + else { + Write-CMLogEntry -Value "BIOS is already up to date with the latest $($PackageList[0].PackageVersion) version" -Severity 1 + } + } + else { + Write-CMLogEntry -Value "Task sequence engine would have been instructed to download package ID $($PackageList[0].PackageID) to %_SMSTSMDataPath%\BIOSPackage" -Severity 1 + } - } elseif ($PackageList.Count -ge 2) { - Write-CMLogEntry -Value "BIOS package list contains multiple matches, attempting to set task sequence variable" -Severity 1 + } + elseif ($PackageList.Count -ge 2) { + Write-CMLogEntry -Value "BIOS package list contains multiple matches, attempting to set task sequence variable" -Severity 1 - # Determine the latest BIOS package by creation date - if ($ComputerManufacturer -match "Dell") { - $PackageList = $PackageList | Sort-Object -Property SourceDate -Descending | Select-Object -First 1 - } elseif ($ComputerManufacturer -eq "Lenovo") { - $ComputerDescription = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version - # Attempt to find exact model match for Lenovo models which overlap model types - $PackageList = $PackageList | Where-object { + # Determine the latest BIOS package by creation date + if ($ComputerManufacturer -match "Dell") { + [array]$PackageList = $PackageList | Sort-Object -Property SourceDate -Descending | Select-Object -First 1 + } + elseif ($ComputerManufacturer -eq "Lenovo") { + $ComputerDescription = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version + # Attempt to find exact model match for Lenovo models which overlap model types + [array]$PackageList = $PackageList | Where-Object { ($_.Name -like "*$ComputerDescription") -and ($_.Manufacturer -match $ComputerManufacturer) - } | Sort-object -Property SourceDate -Descending | Select-Object -First 1 + } | Sort-Object -Property SourceDate -Descending | Select-Object -First 1 - If ($PackageList -eq $null) { - # Fall back to select the latest model type match if no model name match is found - $PackageList = $PackageList | Sort-object -Property SourceDate -Descending | Select-Object -First 1 - } - } elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { - # Determine the latest BIOS package by creation date - $PackageList = $PackageList | Sort-Object -Property PackageCreated -Descending | Select-Object -First 1 + If ($PackageList -eq $null) { + # Fall back to select the latest model type match if no model name match is found + [array]$PackageList = $PackageList | Sort-Object -Property SourceDate -Descending | Select-Object -First 1 + } + } + elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { + # Determine the latest BIOS package by creation date + [array]$PackageList = $PackageList | Sort-Object -Property PackageCreated -Descending | Select-Object -First 1 - } elseif ($ComputerManufacturer -match "Microsoft") { - $PackageList = $PackageList | Sort-Object -Property PackageCreated -Descending | Select-Object -First 1 - } - if ($PackageList.Count -eq 1) { - # Check if BIOS package is newer than currently installed - if ($ComputerManufacturer -match "Dell") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Lenovo") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].PackageDescription).Split(":")[2]).Trimend(")") -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer - } elseif ($ComputerManufacturer -match "Microsoft") { - $NewBIOSAvailable = $true - } + } + elseif ($ComputerManufacturer -match "Microsoft") { + [array]$PackageList = $PackageList | Sort-Object -Property PackageCreated -Descending | Select-Object -First 1 + } + if ($PackageList.Count -eq 1) { + # Check if BIOS package is newer than currently installed + if ($ComputerManufacturer -match "Dell") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Lenovo") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].PackageDescription).Split(":")[2]).Trimend(")") -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer + } + elseif ($ComputerManufacturer -match "Microsoft") { + $NewBIOSAvailable = $true + } - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - if ($TSEnvironment.Value("NewBIOSAvailable") -eq $true) { - $DownloadInvocation = Invoke-CMDownloadContent -PackageID $($PackageList[0].PackageID) -DestinationLocationType Custom -DestinationVariableName "OSDBIOSPackage" -CustomLocationPath "%_SMSTSMDataPath%\BIOSPackage" + if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { + if ($TSEnvironment.Value("NewBIOSAvailable") -eq $true) { + $DownloadInvocation = Invoke-CMDownloadContent -PackageID $($PackageList[0].PackageID) -DestinationLocationType Custom -DestinationVariableName "OSDBIOSPackage" -CustomLocationPath "%_SMSTSMDataPath%\BIOSPackage" - try { - # Check for successful package download - if ($DownloadInvocation -eq 0) { - Write-CMLogEntry -Value "BIOS update package content downloaded successfully. Package located in: $($TSEnvironment.Value('OSDBIOSPackage01'))" -Severity 1 - } else { - Write-CMLogEntry -Value "BIOS package content download process returned an unhandled exit code: $($DownloadInvocation)" -Severity 3; exit 13 - } - } catch [System.Exception] { - Write-CMLogEntry -Value "An error occurred while applying BIOS (multiple package match). Error message: $($_.Exception.Message)" -Severity 3; exit 15 - } - } else { - Write-CMLogEntry -Value "BIOS is already up to date with the latest $($PackageList[0].Version) version" -Severity 1 - } - } else { - Write-CMLogEntry -Value "Task sequence engine would have been instructed to download package ID $($PackageList[0].PackageID) to %_SMSTSMDataPath%\BIOSPackage" -Severity 1 - } - } else { - Write-CMLogEntry -Value "Unable to determine a matching BIOS package from list since an unsupported count was returned from package list, bailing out" -Severity 2; exit 1 - } - } else { - Write-CMLogEntry -Value "Empty BIOS package list detected, bailing out" -Severity 1 - } - } else { - Write-CMLogEntry -Value "BIOS package list returned from web service did not contain any objects matching the computer model and manufacturer, bailing out" -Severity 1 - } - } else { - Write-CMLogEntry -Value "This script is supported on Dell, Lenovo and HP systems only at this point, bailing out" -Severity 1 - } - } - } - } + try { + # Check for successful package download + if ($DownloadInvocation -eq 0) { + Write-CMLogEntry -Value "BIOS update package content downloaded successfully. Package located in: $($TSEnvironment.Value('OSDBIOSPackage01'))" -Severity 1 + } + else { + Write-CMLogEntry -Value "BIOS package content download process returned an unhandled exit code: $($DownloadInvocation)" -Severity 3; exit 13 + } + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occurred while applying BIOS (multiple package match). Error message: $($_.Exception.Message)" -Severity 3; exit 15 + } + } + else { + Write-CMLogEntry -Value "BIOS is already up to date with the latest $($PackageList[0].Version) version" -Severity 1 + } + } + else { + Write-CMLogEntry -Value "Task sequence engine would have been instructed to download package ID $($PackageList[0].PackageID) to %_SMSTSMDataPath%\BIOSPackage" -Severity 1 + } + } + else { + Write-CMLogEntry -Value "Unable to determine a matching BIOS package from list since an unsupported count was returned from package list, bailing out" -Severity 2; exit 1 + } + } + else { + Write-CMLogEntry -Value "Empty BIOS package list detected, bailing out" -Severity 1 + } + } + else { + Write-CMLogEntry -Value "BIOS package list returned from web service did not contain any objects matching the computer model and manufacturer, bailing out" -Severity 1 + } + } + else { + Write-CMLogEntry -Value "This script is supported on Dell, Lenovo and HP systems only at this point, bailing out" -Severity 1 + } + } + } + } - Write-CMLogEntry -Value "[ApplyBIOSPackage]: Apply BIOS Package process initiated" -Severity 1 - if ($PSCmdLet.ParameterSetName -like "Debug") { - Write-CMLogEntry -Value " - Apply BIOS package process initiated in debug mode" -Severity 1 - } - Write-CMLogEntry -Value " - Apply BIOS package deployment type: $($PSCmdLet.ParameterSetName)" -Severity 1 - Write-CMLogEntry -Value " - Apply BIOS package operational mode: $($OperationalMode)" -Severity 1 + Write-CMLogEntry -Value "[ApplyBIOSPackage]: Apply BIOS Package process initiated" -Severity 1 + if ($PSCmdLet.ParameterSetName -like "Debug") { + Write-CMLogEntry -Value " - Apply BIOS package process initiated in debug mode" -Severity 1 + } + Write-CMLogEntry -Value " - Apply BIOS package deployment type: $($PSCmdLet.ParameterSetName)" -Severity 1 + Write-CMLogEntry -Value " - Apply BIOS package operational mode: $($OperationalMode)" -Severity 1 - # Set script error preference variable - $ErrorActionPreference = "Stop" + # Set script error preference variable + $ErrorActionPreference = "Stop" - try { - Write-CMLogEntry -Value "[PrerequisiteChecker]: Starting environment prerequisite checker" -Severity 1 + try { + Write-CMLogEntry -Value "[PrerequisiteChecker]: Starting environment prerequisite checker" -Severity 1 - # Determine the deployment type mode for driver package installation - Get-DeploymentType + # Determine the deployment type mode for driver package installation + Get-DeploymentType - # Determine if running on supported computer system type - Get-ComputerSystemType + # Determine if running on supported computer system type + Get-ComputerSystemType - # Determine computer manufacturer, model, SystemSKU and FallbackSKU - $ComputerData = Get-ComputerData + # Determine computer manufacturer, model, SystemSKU and FallbackSKU + $ComputerData = Get-ComputerData - # Validate required computer details have successfully been gathered from WMI - Test-ComputerDetails -InputObject $ComputerData + # Validate required computer details have successfully been gathered from WMI + Test-ComputerDetails -InputObject $ComputerData - # Determine the computer detection method to be used for matching against driver packages - $ComputerDetectionMethod = Set-ComputerDetectionMethod + # Determine the computer detection method to be used for matching against driver packages + $ComputerDetectionMethod = Set-ComputerDetectionMethod - Write-CMLogEntry -Value "[PrerequisiteChecker]: Completed environment prerequisite checker" -Severity 1 + Write-CMLogEntry -Value "[PrerequisiteChecker]: Completed environment prerequisite checker" -Severity 1 - if ($Script:PSCmdLet.ParameterSetName -notlike "XMLPackage") { - Write-CMLogEntry -Value "[AdminService]: Starting AdminService endpoint phase" -Severity 1 + if ($Script:PSCmdLet.ParameterSetName -notlike "XMLPackage") { + Write-CMLogEntry -Value "[AdminService]: Starting AdminService endpoint phase" -Severity 1 - # Detect AdminService endpoint type - Write-CMLogEntry -Value "- Detecting AdminService endpoint type" -Severity 1 - Get-AdminServiceEndpointType + # Detect AdminService endpoint type + Write-CMLogEntry -Value "- Detecting AdminService endpoint type" -Severity 1 + Get-AdminServiceEndpointType - # Determine if required values to connect to AdminService are provided - Test-AdminServiceData + # Determine if required values to connect to AdminService are provided + Test-AdminServiceData - # Determine the AdminService endpoint URL based on endpoint type - Write-CMLogEntry -Value "- Detecting AdminService URL" -Severity 1 - Set-AdminServiceEndpointURL + # Determine the AdminService endpoint URL based on endpoint type + Write-CMLogEntry -Value "- Detecting AdminService URL" -Severity 1 + Set-AdminServiceEndpointURL - # Construct PSCredential object for AdminService authentication, this is required for both endpoint types - Write-CMLogEntry -Value "- Constructing AdminService authentication" -Severity 1 - Get-AuthCredential + # Construct PSCredential object for AdminService authentication, this is required for both endpoint types + Write-CMLogEntry -Value "- Constructing AdminService authentication" -Severity 1 + Get-AuthCredential - # Attempt to retrieve an authentication token for external AdminService endpoint connectivity - # This will only execute when the endpoint type has been detected as External, which means that authentication is needed against the Cloud Management Gateway - if ($Script:AdminServiceEndpointType -like "External") { - Get-AuthToken - } + # Attempt to retrieve an authentication token for external AdminService endpoint connectivity + # This will only execute when the endpoint type has been detected as External, which means that authentication is needed against the Cloud Management Gateway + if ($Script:AdminServiceEndpointType -like "External") { + Get-AuthToken + } - Write-CMLogEntry -Value "[AdminService]: Completed AdminService endpoint phase" -Severity 1 - } - Write-CMLogEntry -Value "[BIOSPackage]: Starting BIOS package retrieval using method: $($Script:PackageSource)" -Severity 1 + Write-CMLogEntry -Value "[AdminService]: Completed AdminService endpoint phase" -Severity 1 + } + Write-CMLogEntry -Value "[BIOSPackage]: Starting BIOS package retrieval using method: $($Script:PackageSource)" -Severity 1 - # Retrieve available BIOS packages from admin service - $BIOSPackages = Get-BIOSPackages + # Retrieve available BIOS packages from admin service + $BIOSPackages = Get-BIOSPackages - # Get existing BIOS version - $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() - Write-CMLogEntry -Value "Current BIOS version determined as: $($CurrentBIOSVersion)" -Severity 1 - $ComputerData = $ComputerData | Select-Object -first 1 + # Get existing BIOS version + $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() + Write-CMLogEntry -Value "Current BIOS version determined as: $($CurrentBIOSVersion)" -Severity 1 + $ComputerData = $ComputerData | Select-Object -First 1 - # Determine if a newer BIOS release is available - Get-BIOSUpdate -InputObject $ComputerData - Write-CMLogEntry -Value "[BIOSPackage]: Completed BIOS package matching phase" -Severity 1 - Write-CMLogEntry -Value "[BIOSPackageValidation]: Completed BIOS package validation phase" -Severity 1 + # Determine if a newer BIOS release is available + Get-BIOSUpdate -InputObject $ComputerData + Write-CMLogEntry -Value "[BIOSPackage]: Completed BIOS package matching phase" -Severity 1 + Write-CMLogEntry -Value "[BIOSPackageValidation]: Completed BIOS package validation phase" -Severity 1 - } catch [System.Exception] { - Write-CMLogEntry -Value "[BIOSPackage]: BIOS detection process failed, please refer to previous error or warning messages" -Severity 3 + } + catch [System.Exception] { + Write-CMLogEntry -Value "[BIOSPackage]: BIOS detection process failed, please refer to previous error or warning messages" -Severity 3 - # Main try-catch block was triggered, this should cause the script to fail with exit code 1 - exit 1 - } + # Main try-catch block was triggered, this should cause the script to fail with exit code 1 + exit 1 + } } End { - if ($PSCmdLet.ParameterSetName -notlike "Debug") { - # Reset OSDDownloadContent.exe dependant variables for further use of the task sequence step - Invoke-CMResetDownloadContentVariables - } + if ($PSCmdLet.ParameterSetName -notlike "Debug") { + # Reset OSDDownloadContent.exe dependant variables for further use of the task sequence step + Invoke-CMResetDownloadContentVariables + } - # Write final output to log file - Write-CMLogEntry -Value "[ApplyBIOSPackage]: Completed Apply BIOS Package process" -Severity 1 + # Write final output to log file + Write-CMLogEntry -Value "[ApplyBIOSPackage]: Completed Apply BIOS Package process" -Severity 1 } From d2016e638ff693907758238512017e1e35b61b89 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Mon, 11 Jul 2022 08:09:32 -0300 Subject: [PATCH 09/14] Delete Check for BIOS Updates.ps1 --- Check for BIOS Updates.ps1 | 316 ------------------------------------- 1 file changed, 316 deletions(-) delete mode 100644 Check for BIOS Updates.ps1 diff --git a/Check for BIOS Updates.ps1 b/Check for BIOS Updates.ps1 deleted file mode 100644 index a41410a..0000000 --- a/Check for BIOS Updates.ps1 +++ /dev/null @@ -1,316 +0,0 @@ -# Attempts to construst TSEnvironment object -# Load Microsoft.SMS.TSEnvironment COM object -try { - $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Continue -} -catch [System.Exception] { - #Write-CMLogEntry -Value "Not in a TSEnvironment, we must be testing from Windows" -Severity 1 -} - -#Provides logging in CMTrace style (from sccconfigmgr.com) -if ($TSEnvironment) { - $LogsDirectory = $Script:TSEnvironment.Value("_SMSTSLogPath") - -} -else { - $LogsDirectory = Join-Path $env:SystemRoot "Temp" - -} -function Write-CMLogEntry { - - param ( - [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] - [ValidateNotNullOrEmpty()] - [string]$Value, - [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] - [ValidateNotNullOrEmpty()] - [ValidateSet("1", "2", "3")] - [string]$Severity, - [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] - [ValidateNotNullOrEmpty()] - [string]$FileName = "BIOS Maintenance.log" - ) - # Determine log file location - $LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName - - # Construct time stamp for log entry - if (-not (Test-Path -Path 'variable:global:TimezoneBias')) { - [string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes - if ($TimezoneBias -match "^-") { - $TimezoneBias = $TimezoneBias.Replace('-', '+') - } - else { - $TimezoneBias = '-' + $TimezoneBias - } - } - $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias) - - # Construct date for log entry - $Date = (Get-Date -Format "MM-dd-yyyy") - - # Construct context for log entry - $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - - # Construct final log entry - $LogText = "" - - # Add value to log file - try { - - Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop - } - catch [System.Exception] { - Write-Warning -Message "Unable to append log entry to $FileName. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" - } -} - -function Compare-BIOSVersion { - param ( - [parameter(Mandatory = $false, HelpMessage = "Current available BIOS version.")] - [ValidateNotNullOrEmpty()] - [string]$AvailableBIOSVersion, - [parameter(Mandatory = $false, HelpMessage = "Current available BIOS revision date.")] - [string]$AvailableBIOSReleaseDate, - [parameter(Mandatory = $true, HelpMessage = "Current available BIOS version.")] - [ValidateNotNullOrEmpty()] - [string]$ComputerManufacturer - ) - - if ($ComputerManufacturer -match "Dell") { - # Obtain current BIOS release - $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() - Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release deteced as $($AvailableBIOSVersion)." -Severity 1 - - # Determine Dell BIOS revision format - if ($CurrentBIOSVersion -like "*.*.*") { - # Compare current BIOS release to available - if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - elseif ($CurrentBIOSVersion -like "A*") { - # Compare current BIOS release to available - if ($AvailableBIOSVersion -like "*.*.*") { - # Assume that the bios is new as moving from Axx to x.x.x formats - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - elseif ($AvailableBIOSVersion -gt $CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - } - - if ($ComputerManufacturer -match "Lenovo") { - # Obtain current BIOS release - $CurrentBIOSReleaseDate = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) - Write-CMLogEntry -Value "Current BIOS release date detected as $($CurrentBIOSReleaseDate)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release date detected as $($AvailableBIOSReleaseDate)." -Severity 1 - - # Compare current BIOS release to available - if ($AvailableBIOSReleaseDate -gt $CurrentBIOSReleaseDate) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current date release dated $($CurrentBIOSReleaseDate) will be replaced by release $($AvailableBIOSReleaseDate)." -Severity 1 - } - } - - if ($ComputerManufacturer -match "Hewlett-Packard|HP") { - # Obtain current BIOS release - $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) - - # Update version formatting - $AvailableBIOSVersion = $AvailableBIOSVersion.TrimEnd(".") - $AvailableBIOSVersion = $AvailableBIOSVersion.Split(" ")[0] - - # Detect new versus old BIOS formats - switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { - "*ver*" { - if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { - $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() - $BIOSVersionParseable = $false - } - else { - $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) - $BIOSVersionParseable = $true - } - } - default { - $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" - $BIOSVersionParseable = $true - } - } - - # Output version details - Write-CMLogEntry -Value "Current BIOS release detected as $($CurrentBIOSVersion)." -Severity 1 - Write-CMLogEntry -Value "Available BIOS release detected as $($AvailableBIOSVersion)." -Severity 1 - - # Compare current BIOS release to available - switch ($BIOSVersionParseable) { - $true { - if ([System.Version]$AvailableBIOSVersion -gt [System.Version]$CurrentBIOSVersion) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - $false { - if ([System.Int32]::Parse($AvailableBIOSVersion.TrimStart("F.")) -gt [System.Int32]::Parse($CurrentBIOSVersion.TrimStart("F."))) { - # Write output to task sequence variable - if ($Script:PSCmdlet.ParameterSetName -notlike "Debug") { - $TSEnvironment.Value("NewBIOSAvailable") = $true - } - Write-CMLogEntry -Value "A new version of the BIOS has been detected. Current release $($CurrentBIOSVersion) will be replaced by $($AvailableBIOSVersion)." -Severity 1 - } - } - } - } -} - - -# Instantiates connection to ASD-Webservice using API key -$URI = $TSEnvironment.Value("ASDWebServiceURI").Replace('/osd', '') -$SecretKey = $TSEnvironment.Value("ASDWebServiceKey") -Write-CMLogEntry -Value "[INFO] URI retrieved: $URI" -Severity 1 - -# $Manufacturer = $WMIObjectWin32Computer.Manufacturer -$WMIObjectWin32Computer = (Get-WmiObject -Class Win32_ComputerSystem) - -$Manufacturer = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Manufacturer).Trim() -switch -Wildcard ($Manufacturer) { - "*Microsoft*" { - $Manufacturer = "Microsoft" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - } - "*HP*" { - $Manufacturer = "HP" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) - $BIOSVersionProperty = 'Version' - } - "*Hewlett-Packard*" { - $Manufacturer = "Hewlett-Packard" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $CurrentBIOSProperties = (Get-WmiObject -Class Win32_BIOS | Select-Object -Property *) - $BIOSVersionProperty = 'Version' - } - "*Dell*" { - $Manufacturer = "Dell" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - $CurrentBIOSVersion = (Get-WmiObject -Class Win32_BIOS | Select-Object -ExpandProperty SMBIOSBIOSVersion).Trim() - $BIOSVersionProperty = 'Version' - } - "*Lenovo*" { - $Manufacturer = "Lenovo" - $Model = (Get-WmiObject -Class "Win32_ComputerSystemProduct" | Select-Object -ExpandProperty Version).Trim() - $CurrentBIOSVersion = ((Get-WmiObject -Class Win32_BIOS | Select-Object -Property *).ReleaseDate).SubString(0, 8) - $BIOSVersionProperty = 'Description' - } - "*Panasonic*" { - $Manufacturer = "Panasonic Corporation" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - } - "*Viglen*" { - $Manufacturer = "Viglen" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - } - "*AZW*" { - $Manufacturer = "AZW" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - } - "*Fujitsu*" { - $Manufacturer = "Fujitsu" - $Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() - } - default { - $Manufacturer = $WMIObjectWin32Computer.Manufacturer - $Model = $WMIObjectWin32Computer.Model - } -} - -# Detect new versus old BIOS formats -if ($Manufacturer -match "Hewlett-Packard|HP") { - switch -wildcard ($($CurrentBIOSProperties.SMBIOSBIOSVersion)) { - "*ver*" { - if ($CurrentBIOSProperties.SMBIOSBIOSVersion -match '.F.\d+$') { - $CurrentBIOSVersion = ($CurrentBIOSProperties.SMBIOSBIOSVersion -split "Ver.")[1].Trim() - $BIOSVersionParseable = $false - } - else { - $CurrentBIOSVersion = [System.Version]::Parse(($CurrentBIOSProperties.SMBIOSBIOSVersion).TrimStart($CurrentBIOSProperties.SMBIOSBIOSVersion.Split(".")[0]).TrimStart(".").Trim().Split(" ")[0]) - $BIOSVersionParseable = $true - } - } - default { - $CurrentBIOSVersion = "$($CurrentBIOSProperties.SystemBiosMajorVersion).$($CurrentBIOSProperties.SystemBiosMinorVersion)" - $BIOSVersionParseable = $true - } - } -} - - -$APICallParams = @{ - Headers = @{ - "Content-Type" = "application/json" - "Authorization" = "Bearer $($SecretKey)" - } - Method = 'GET' - URI = "$URI/reports/Get-CMBIOSPackage?Model=$Model" - ErrorAction = "SilentlyContinue" -} - -Write-CMLogEntry -Value "[INFO] Calling API for BIOS package information: $APICallParams with model $Model" -Severity 1 -$APIResults = (Invoke-RestMethod @APICallParams) -$AvailableBIOSVersion = $APIResults.$BIOSVersionProperty - -switch ($BIOSVersionProperty) { - 'Description' { - $AvailableBIOSVersion = $AvailableBIOSVersion.Split(':')[2].Split(')')[0] - Compare-BIOSVersion -AvailableBIOSReleaseDate $AvailableBIOSVersion -ComputerManufacturer $Manufacturer - } - 'Version' { - Compare-BIOSVersion -AvailableBIOSVersion $AvailableBIOSVersion -ComputerManufacturer $Manufacturer - } -} - -if ($APIResults.Description -match '=') -{ - Write-CMLogEntry -Value "[INFO] Special BIOS detected. Checking for conditions (Phase or prereq)" -Severity 1 - $Object = $APIResults.Description.Split(")") - $Object | ForEach-Object - { - switch -Wildcard ($PSItem) - { - "*Phase" - { - $Phase = $PSItem.Split('=')[1] - $TSEnvironment.Value("BIOSPhase") = $Phase - Write-CMLogEntry -Value "[INFO] Special BIOS detected. Must run in $Phase" -Severity 1 - } - "*PreReq" - { - $PreReq = $PSItem.Split('=')[1] - $TSEnvironment.Value("BIOSPreReq") = $PreReq - Write-CMLogEntry -Value "[INFO] Special BIOS detected. PreReq Version detected $PreReq" -Severity 1 - } - } - } -} - -Write-CMLogEntry -Value "[INFO] API call results: $AvailableBIOSVersion" -Severity 1 \ No newline at end of file From 6a5e6fadb963e385c170b9167d34a29c8c504c34 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Mon, 11 Jul 2022 13:16:03 -0300 Subject: [PATCH 10/14] Update Invoke-CMDownloadBIOSPackage.ps1 Fixed issue with Lenovo BIOS version and additional text in description --- Invoke-CMDownloadBIOSPackage.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Invoke-CMDownloadBIOSPackage.ps1 b/Invoke-CMDownloadBIOSPackage.ps1 index fbe4829..63ce1b7 100644 --- a/Invoke-CMDownloadBIOSPackage.ps1 +++ b/Invoke-CMDownloadBIOSPackage.ps1 @@ -72,6 +72,7 @@ 3.0.3 - (2020-12-10) - Fixed issue in WinPE, with addition of baremetal parameter switch (now default) Added BIOSUpdate parameter switch for Full OS deployments 3.0.4 - (2022-07-05) - Fixed issue detecting older Dells without SKU or fallback SKU + 3.0.5 = (2022-07-11) - Fixed issue with Lenovo BIOS version and additional text in description #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = "BareMetal")] @@ -1178,7 +1179,7 @@ Process { Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer } elseif ($ComputerManufacturer -match "Lenovo") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].Description).Split(":")[2].Trimend(")")) -ComputerManufacturer $ComputerManufacturer + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].Description).Split(":")[2].Split(')')[0]) -ComputerManufacturer $ComputerManufacturer } elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer @@ -1247,7 +1248,7 @@ Process { Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer } elseif ($ComputerManufacturer -match "Lenovo") { - Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].PackageDescription).Split(":")[2]).Trimend(")") -ComputerManufacturer $ComputerManufacturer + Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -AvailableBIOSReleaseDate $(($PackageList[0].Description).Split(":")[2]).Split(')')[0] -ComputerManufacturer $ComputerManufacturer } elseif ($ComputerManufacturer -match "Hewlett-Packard|HP") { Compare-BIOSVersion -AvailableBIOSVersion $PackageList[0].Version -ComputerManufacturer $ComputerManufacturer From 32d8fd555042439444c38b18928c3f901ab662ee Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Mon, 11 Jul 2022 13:33:40 -0300 Subject: [PATCH 11/14] Update Invoke-CMDownloadBIOSPackage.ps1 Fixing version information --- Invoke-CMDownloadBIOSPackage.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Invoke-CMDownloadBIOSPackage.ps1 b/Invoke-CMDownloadBIOSPackage.ps1 index 63ce1b7..d749269 100644 --- a/Invoke-CMDownloadBIOSPackage.ps1 +++ b/Invoke-CMDownloadBIOSPackage.ps1 @@ -62,7 +62,7 @@ Author: Nickolaj Andersen / Maurice Daly Contact: @NickolajA / @MoDaly_IT Created: 2020-10-30 - Updated: 2020-10-30 + Updated: 2022-07-11 Version history: 3.0.0 - (2020-10-30) - Script created @@ -72,7 +72,7 @@ 3.0.3 - (2020-12-10) - Fixed issue in WinPE, with addition of baremetal parameter switch (now default) Added BIOSUpdate parameter switch for Full OS deployments 3.0.4 - (2022-07-05) - Fixed issue detecting older Dells without SKU or fallback SKU - 3.0.5 = (2022-07-11) - Fixed issue with Lenovo BIOS version and additional text in description + 3.0.5 - (2022-07-11) - Fixed issue with Lenovo BIOS version and additional text in description #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = "BareMetal")] @@ -832,7 +832,10 @@ Process { $ComputerDetails.Model = (Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty Model).Trim() $ComputerDetails.SystemSKU = (Get-CimInstance -ClassName "MS_SystemInformation" -Namespace "root\WMI").SystemSku.Trim() [string]$OEMString = Get-WmiObject -Class "Win32_ComputerSystem" | Select-Object -ExpandProperty OEMStringArray - $ComputerDetails.FallbackSKU = [regex]::Matches($OEMString, '\[\S*]')[0].Value.TrimStart("[").TrimEnd("]") + if (!($OEMString -eq 'www.dell.com')) { + $ComputerDetails.FallbackSKU = [regex]::Matches($OEMString, '\[\S*]')[0].Value.TrimStart("[").TrimEnd("]") + } + } "*Lenovo*" { $ComputerDetails.Manufacturer = "Lenovo" @@ -1092,6 +1095,7 @@ Process { # Define machine matching values $ComputerSystemType = $InputObject.Model $ComputerManufacturer = $InputObject.Manufacturer + $ComputerModel = $InputObject.Model $SystemSKU = $InputObject.SystemSKU # Supported manufacturers From 59209315689b168fbbe187b4844ea633c39942b4 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Fri, 22 Jul 2022 14:51:23 -0300 Subject: [PATCH 12/14] Update Invoke-DellBIOSUpdate.ps1 Add support for non-flash64 systems and detection of low battery and forceit flag --- Invoke-DellBIOSUpdate.ps1 | 394 ++++++++++++++++++++++---------------- 1 file changed, 231 insertions(+), 163 deletions(-) diff --git a/Invoke-DellBIOSUpdate.ps1 b/Invoke-DellBIOSUpdate.ps1 index ed088bb..01a7547 100644 --- a/Invoke-DellBIOSUpdate.ps1 +++ b/Invoke-DellBIOSUpdate.ps1 @@ -1,4 +1,4 @@ -<# +<# .SYNOPSIS Invoke Dell BIOS Update process. @@ -22,7 +22,7 @@ Authors: Maurice Daly & Nickolaj Andersen Contact: @modaly_it Created: 2017-05-30 - Updated: 2019-05-14 + Updated: 2022-07-22 Version history: 1.0.0 - (2017-05-30) Script created (Maurice Daly) @@ -37,204 +37,272 @@ 1.0.8 - (2019-03-02) Updated path and task sequence handling 1.0.9 - (2019-05-01) Removed the /f switch that bypasses the model check and could possibly incorrectly flash the system with a wrong BIOS package if Dell somehow messes up with the downloaded bits 1.1.0 - (2019-05-14) Handle log output correctly if $Password is not specified + 1.2.1 - (2022-07-22) -Added support for systems without a Flash64 option + -Added detection of battery issues for non-flash64 systems and retry with /forceit #> -[CmdletBinding(SupportsShouldProcess=$true)] -param( - [parameter(Mandatory=$false, HelpMessage="Specify the path containing the Flash64W.exe and BIOS executable.")] +[CmdletBinding(SupportsShouldProcess = $true)] +param ( + [parameter(Mandatory = $false, HelpMessage = "Specify the path containing the Flash64W.exe and BIOS executable.")] [ValidateNotNullOrEmpty()] [string]$Path, - - [parameter(Mandatory=$false, HelpMessage="Specify the BIOS password if necessary.")] + [parameter(Mandatory = $false, HelpMessage = "Specify the BIOS password if necessary.")] [ValidateNotNullOrEmpty()] [string]$Password, - - [parameter(Mandatory=$false, HelpMessage="Set the name of the log file produced by the flash utility.")] + [parameter(Mandatory = $false, HelpMessage = "Set the name of the log file produced by the flash utility.")] [ValidateNotNullOrEmpty()] [string]$LogFileName = "DellFlashBIOSUpdate.log" ) Begin { - # Load Microsoft.SMS.TSEnvironment COM object - try { - $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop - } - catch [System.Exception] { - Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object" - } + # Load Microsoft.SMS.TSEnvironment COM object + try { + $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object" + } } Process { # Functions function Write-CMLogEntry { - param( - [parameter(Mandatory=$true, HelpMessage="Value added to the log file.")] - [ValidateNotNullOrEmpty()] - [string]$Value, - - [parameter(Mandatory=$true, HelpMessage="Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] - [ValidateNotNullOrEmpty()] + param ( + [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] + [ValidateNotNullOrEmpty()] + [string]$Value, + [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] + [ValidateNotNullOrEmpty()] [ValidateSet("1", "2", "3")] - [string]$Severity, - - [parameter(Mandatory=$false, HelpMessage="Name of the log file that the entry will written to.")] - [ValidateNotNullOrEmpty()] - [string]$FileName = "Invoke-DellBIOSUpdate.log" - ) - # Determine log file location + [string]$Severity, + [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] + [ValidateNotNullOrEmpty()] + [string]$FileName = "Invoke-DellBIOSUpdate.log" + ) + # Determine log file location $LogFilePath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $FileName - + # Construct time stamp for log entry $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), "+", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) - + # Construct date for log entry $Date = (Get-Date -Format "MM-dd-yyyy") - + # Construct context for log entry $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - + # Construct final log entry $LogText = "" - - # Add value to log file + + # Add value to log file try { - Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop + Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop } catch [System.Exception] { Write-Warning -Message "Unable to append log entry to Invoke-DellBIOSUpdate.log file. Error message: $($_.Exception.Message)" } } - # Default to task sequence variable set in detection script - if (-not([string]::IsNullOrEmpty($TSEnvironment.Value("OSDBIOSPackage01")))){ - Write-CMLogEntry -Value "Using BIOS package location set in OSDBIOSPackage01 TS variable" -Severity 1 - $Path = $TSEnvironment.Value("OSDBIOSPackage01") - } + # Default to task sequence variable set in detection script + if (-not ([string]::IsNullOrEmpty($TSEnvironment.Value("OSDBIOSPackage01")))) { + Write-CMLogEntry -Value "Using BIOS package location set in OSDBIOSPackage01 TS variable" -Severity 1 + $Path = $TSEnvironment.Value("OSDBIOSPackage01") + } - # Run BIOS update process if BIOS package exists - if (-not([string]::IsNullOrEmpty($Path))){ - - # Write log file for script execution - Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for Dell BIOS updates" -Severity 1 - - # Flash BIOS upgrade utility file name - $FlashUtility = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "Flash64W.exe" } | Select-Object -ExpandProperty FullName - Write-CMLogEntry -Value "Attempting to use flash utility: $($FlashUtility)" -Severity 1 - - if ($FlashUtility -ne $null) { - # Detect BIOS update executable - $CurrentBIOSFile = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -notlike ($FlashUtility | Split-Path -leaf) } | Select-Object -ExpandProperty FullName - Write-CMLogEntry -Value "Attempting to use BIOS update file: $($CurrentBIOSFile)" -Severity 1 - - if ($CurrentBIOSFile -ne $null) { - # Set log file location - $BIOSLogFile = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName - - # Set required switches for silent upgrade of the bios and logging - $FlashSwitches = "/b=$($CurrentBIOSFile) /s /l=$($BIOSLogFile)" - - # Add password to the Flash64W.exe switches - if ($PSBoundParameters["Password"]) { - if (-not([System.String]::IsNullOrEmpty($Password))) { - $FlashSwitches = $FlashSwitches + " /p=$($Password)" - } - } + # Run BIOS update process if BIOS package exists + if (-not ([string]::IsNullOrEmpty($Path))) { + + # Write log file for script execution + Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for Dell BIOS updates" -Severity 1 + + # Flash BIOS upgrade utility file name + $FlashUtility = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "Flash64W.exe" } | Select-Object -ExpandProperty FullName + Write-CMLogEntry -Value "Attempting to use flash utility: $($FlashUtility)" -Severity 1 + + if ($FlashUtility -ne $null) { + # Detect BIOS update executable + $CurrentBIOSFile = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -notlike ($FlashUtility | Split-Path -Leaf) } | Select-Object -ExpandProperty FullName + Write-CMLogEntry -Value "Attempting to use BIOS update file: $($CurrentBIOSFile)" -Severity 1 + + if ($CurrentBIOSFile -ne $null) { + # Set log file location + $BIOSLogFile = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName + + # Set required switches for silent upgrade of the bios and logging + $FlashSwitches = "/b=$($CurrentBIOSFile) /s /l=$($BIOSLogFile)" # /forceit + + # Add password to the Flash64W.exe switches + if ($PSBoundParameters["Password"]) { + if (-not ([System.String]::IsNullOrEmpty($Password))) { + $FlashSwitches = $FlashSwitches + " /p=$($Password)" + } + } + + if (($TSEnvironment -ne $null) -and ($TSEnvironment.Value("_SMSTSinWinPE") -eq $true)) { + Write-CMLogEntry -Value "Current environment is determined as WinPE" -Severity 1 + + try { + # Start flash update process + if (-not ([System.String]::IsNullOrEmpty($Password))) { + Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches -replace $Password, "")" -Severity 1 + } + else { + Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches)" -Severity 1 + } + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + + # Set reboot flag if restart required determined (exit code 2) - if (($TSEnvironment -ne $null) -and ($TSEnvironment.Value("_SMSTSinWinPE") -eq $true)) { - Write-CMLogEntry -Value "Current environment is determined as WinPE" -Severity 1 - try { - # Start flash update process - if (-not([System.String]::IsNullOrEmpty($Password))) { - Write-CMLogEntry -Value "Using the following switches for Flash64W.exe: $($FlashSwitches -replace $Password, "")" -Severity 1 - } - else { - Write-CMLogEntry -Value "Using the following switches for Flash64W.exe: $($FlashSwitches)" -Severity 1 - } - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait -ErrorAction Stop - - # Set reboot flag if restart required determined (exit code 2) - if ($FlashProcess.ExitCode -match "0|2") { - # Set reboot required flag - $TSEnvironment.Value("SMSTSBIOSUpdateRebootRequired") = "True" - $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" - } - elseif ($FlashProcess.ExitCode -eq "10") { - Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3; exit 1 - } - else { - Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Please review the log file located at $($BIOSLogFile)" -Severity 3; exit 1 - } - - } - catch [System.Exception] { - Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Error message: $($_.Exception.Message)" -Severity 3 ; exit 1 - } - } - else { - # Used as a fall back for systems that do not support the Flash64w update tool - # Used in a later section of the task sequence (after Setup Windows and ConfigMgr step) + switch ($FlashProcess.ExitCode) { + "0" { + # Set reboot required flag + $TSEnvironment.Value("SMSTSBIOSUpdateRebootRequired") = "True" + $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" + } + "2" { + # Set reboot required flag + $TSEnvironment.Value("SMSTSBIOSUpdateRebootRequired") = "True" + $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" + } + "10" { + Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3; exit 1 + } + default { + Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Please review the log file located at $($BIOSLogFile)" -Severity 3; exit 1 + } + } - Write-CMLogEntry -Value "Current environment is determined as FullOS" -Severity 1 + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 + } + } + else { + # Used as a fall back for systems that do not support the Flash64w update tool + # Used in a later section of the task sequence (after Setup Windows and ConfigMgr step) - # Detect Bitlocker Status - $OSVolumeEncypted = if ((Manage-Bde -Status C:) -match "Protection On") { Write-Output $true } else { Write-Output $false } + Write-CMLogEntry -Value "Current environment is determined as FullOS" -Severity 1 - # Supend Bitlocker if $OSVolumeEncypted is $true, remember to re-enable BitLocker after the flashing has occurred - if ($OSVolumeEncypted -eq $true) { - Write-CMLogEntry -Value "Suspending BitLocker protected volume: C:" -Severity 1 - Manage-Bde -Protectors -Disable C: - } + # Detect Bitlocker Status + $OSVolumeEncypted = if ((Manage-Bde -Status C:) -match "Protection On") { Write-Output $true } + else { Write-Output $false } - # Start BIOS update process - try { - if (([Environment]::Is64BitOperatingSystem) -eq $true) { - Write-CMLogEntry -Value "Starting 64-bit flash BIOS update process" -Severity 1 - if (-not([System.String]::IsNullOrEmpty($Password))) { - Write-CMLogEntry -Value "Using the following switches for Flash64W.exe: $($FlashSwitches -replace $Password, "")" -Severity 1 - } - else { - Write-CMLogEntry -Value "Using the following switches for Flash64W.exe: $($FlashSwitches)" -Severity 1 - } - - # Update BIOS using Flash64W.exe - $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -Passthru -Wait -ErrorAction Stop - } - else { - # Set required switches for silent upgrade of the BIOS - $FileSwitches = " /l=$($BIOSLogFile) /s" + # Supend Bitlocker if $OSVolumeEncypted is $true, remember to re-enable BitLocker after the flashing has occurred + if ($OSVolumeEncypted -eq $true) { + Write-CMLogEntry -Value "Suspending BitLocker protected volume: C:" -Severity 1 + Manage-Bde -Protectors -Disable C: + } + + # Start BIOS update process + try { + if (([Environment]::Is64BitOperatingSystem) -eq $true) { + Write-CMLogEntry -Value "Starting 64-bit flash BIOS update process" -Severity 1 + if (-not ([System.String]::IsNullOrEmpty($Password))) { + Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches -replace $Password, "")" -Severity 1 + } + else { + Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches)" -Severity 1 + } + + # Update BIOS using Flash64W.exe + $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop - # Add password to switches - if ($PSBoundParameters["Password"]) { - if (-not([System.String]::IsNullOrEmpty($Password))) { - $FileSwitches = $FileSwitches + " /p=$($Password)" - } - } + switch ($FlashUpdate.ExitCode) { + "0" { + # Set reboot required flag + $TSEnvironment.Value("SMSTSBIOSUpdateRebootRequired") = "True" + $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" + } + "2" { + # Set reboot required flag + $TSEnvironment.Value("SMSTSBIOSUpdateRebootRequired") = "True" + $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" + } + "10" { + Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3; exit 1 + } + default { + Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Please review the log file located at $($BIOSLogFile)" -Severity 3; exit 1 + } + } + } + else { + # Set required switches for silent upgrade of the BIOS + $FileSwitches = " /l=$($BIOSLogFile) /s" + + # Add password to switches + if ($PSBoundParameters["Password"]) { + if (-not ([System.String]::IsNullOrEmpty($Password))) { + $FileSwitches = $FileSwitches + " /p=$($Password)" + } + } + + Write-CMLogEntry -Value "Starting 32-bit flash BIOS update process" -Severity 1 + if (-not ([System.String]::IsNullOrEmpty($Password))) { + Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FlashSwitches -replace $Password, "")" -Severity 1 + } + else { + Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FlashSwitches)" -Severity 1 + } + + # Update BIOS using update file + $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop + } + + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occured while updating the system BIOS in OS online phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 + } + } + } + else { + Write-CMLogEntry -Value "Unable to locate the current BIOS update file" -Severity 2; exit 1 + } + } + else { + $CurrentBIOSFile = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -match ".exe" } | Select-Object -ExpandProperty FullName + + Write-CMLogEntry -Value "Unable to locate the Flash64W.exe utility trying Manual Install" -Severity 1; + # Set log file location + $BIOSLogFile = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName + # Expected battery error for manual process + $BatteryError = ' The battery must be charged above 10% before the system BIOS can be flashed.' + + # Set required switches for silent upgrade of the BIOS + #$FileSwitches = "/s /r" + $FileSwitches = "/s /l=$($BIOSLogFile)" + + # Add password to switches + if ($PSBoundParameters["Password"]) { + if (-not ([System.String]::IsNullOrEmpty($Password))) { + $FileSwitches = $FileSwitches + " /p=$($Password)" + } + } + + Write-CMLogEntry -Value "Starting 32-bit flash BIOS update process" -Severity 1 + if (-not ([System.String]::IsNullOrEmpty($Password))) { + Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FileSwitches -replace $Password, "")" -Severity 1 + } + else { + Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FileSwitches)" -Severity 1 + Write-Host $FileSwitches + + } + + # Update BIOS using update file + $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop - Write-CMLogEntry -Value "Starting 32-bit flash BIOS update process" -Severity 1 - if (-not([System.String]::IsNullOrEmpty($Password))) { - Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches -replace $Password, "")" -Severity 1 - } - else { - Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches)" -Severity 1 - } + if ($FileUpdate.ExitCode -eq 1) { + $ResultsArray = (Get-Content $BIOSLogFile).Split(':') + if ($ResultsArray -like $BatteryError) { + Write-CMLogEntry -Value "Battery error detected, adding /forceit switch and retrying" -Severity 2 + $FileSwitches = $FileSwitches + " /forceit" + $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop + } + } - # Update BIOS using update file - $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop - } - - } - catch [System.Exception] { - Write-CMLogEntry -Value "An error occured while updating the system BIOS in OS online phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 - } - } - } - else { - Write-CMLogEntry -Value "Unable to locate the current BIOS update file" -Severity 2 ; exit 1 - } - } - else { - Write-CMLogEntry -Value "Unable to locate the Flash64W.exe utility" -Severity 2 ; exit 1 - } - } - else { - Write-CMLogEntry -Value "Unable to determine BIOS package path." -Severity 2 ; exit 1 - } -} \ No newline at end of file + Write-CMLogEntry "Flash of $CurrentBIOSFile completed with exit code $($FileUpdate.ExitCode)" + } + } + else { + Write-CMLogEntry -Value "Unable to determine BIOS package path." -Severity 2; exit 1 + } +} From aae642f40ce6e2ae2f40b9d1660efd20da69ddc0 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:09:27 -0300 Subject: [PATCH 13/14] Update Invoke-LenovoBIOSUpdate.ps1 Revised handling for flash utility detection --- Invoke-LenovoBIOSUpdate.ps1 | 366 +++++++++++++++++++----------------- 1 file changed, 189 insertions(+), 177 deletions(-) diff --git a/Invoke-LenovoBIOSUpdate.ps1 b/Invoke-LenovoBIOSUpdate.ps1 index 2beb5d1..f207146 100644 --- a/Invoke-LenovoBIOSUpdate.ps1 +++ b/Invoke-LenovoBIOSUpdate.ps1 @@ -1,31 +1,31 @@ <# .SYNOPSIS Invoke Lenovo BIOS Update process. - + .DESCRIPTION This script will invoke the Lenovo BIOS update process for the executable residing in the path specified for the Path parameter. - + IMPORTANT: This script requires the WinPE-HTA optional component added to the boot image when used during WinPE phase. - + .PARAMETER Path Specify the path containing the WinUPTP or Flash.cmd - + .PARAMETER Password Specify the BIOS password if necessary. - + .PARAMETER LogFileName Set the name of the log file produced by the flash utility. - + .EXAMPLE .\Invoke-LenovoBIOSUpdate.ps1 -Path %OSDBIOSPackage01% -Password "BIOSPassword" - + .NOTES FileName: Invoke-LenovoBIOSUpdate.ps1 Author: Maurice Daly / Nickolaj Andersen Contact: @modaly_it / @NickolajA Created: 2017-06-09 Updated: 2019-05-14 - + Version history: 1.0.0 - (2017-06-09) Script created 1.0.1 - (2017-07-05) Added additional logging, methods and variables @@ -37,185 +37,197 @@ 1.0.7 - (2019-05-01) Extended the search for OLEDLG.dll to include X: for when running from WinPE 1.0.8 - (2019-05-01) Fixed a bug where the script would show an error and fail if the WinUPTP log file could not be found 1.0.9 - (2019-05-14) Handle $Password to check if empty string or null instead of just null value + 1.1.0 - (2022-08-16) Revised handling for flash utility detection #> [CmdletBinding(SupportsShouldProcess = $true)] param ( - [parameter(Mandatory = $true, HelpMessage = "Specify the path containing the Flash64W.exe and BIOS executable.")] - [ValidateNotNullOrEmpty()] - [string]$Path, - [parameter(Mandatory = $false, HelpMessage = "Specify the BIOS password if necessary.")] - [ValidateNotNullOrEmpty()] - [string]$Password, - [parameter(Mandatory = $false, HelpMessage = "Set the name of the log file produced by the flash utility.")] - [ValidateNotNullOrEmpty()] - [string]$LogFileName = "LenovoFlashBiosUpdate.log" + [parameter(Mandatory = $true, HelpMessage = "Specify the path containing the Flash64W.exe and BIOS executable.")] + [ValidateNotNullOrEmpty()] + [string]$Path, + [parameter(Mandatory = $false, HelpMessage = "Specify the BIOS password if necessary.")] + [ValidateNotNullOrEmpty()] + [string]$Password, + [parameter(Mandatory = $false, HelpMessage = "Set the name of the log file produced by the flash utility.")] + [ValidateNotNullOrEmpty()] + [string]$LogFileName = "LenovoFlashBiosUpdate.log" ) Begin { - # Load Microsoft.SMS.TSEnvironment COM object - try { - $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop - } - catch [System.Exception] { - Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object" - } + # Load Microsoft.SMS.TSEnvironment COM object + try { + $TSEnvironment = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object" + } } Process { - # Functions - function Write-CMLogEntry { - param ( - [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] - [ValidateNotNullOrEmpty()] - [string]$Value, - [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] - [ValidateNotNullOrEmpty()] - [ValidateSet("1", "2", "3")] - [string]$Severity, - [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] - [ValidateNotNullOrEmpty()] - [string]$FileName = "Invoke-LenovoBIOSUpdate.log" - ) - # Determine log file location - $LogFilePath = Join-Path -Path $Script:TSEnvironment.Value("_SMSTSLogPath") -ChildPath $FileName - - # Construct time stamp for log entry - $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), "+", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) - - # Construct date for log entry - $Date = (Get-Date -Format "MM-dd-yyyy") - - # Construct context for log entry - $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - - # Construct final log entry - $LogText = "" - - # Add value to log file - try { - Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop - } - catch [System.Exception] { - Write-Warning -Message "Unable to append log entry to Invoke-LenovoBIOSUpdate.log file. Error message: $($_.Exception.Message)" - } - } - - Set-Location -Path $Path - # Write log file for script execution - Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for Lenovo BIOS updates" -Severity 1 - - # Check for required DLL's - if ((Test-Path -Path (Join-Path -Path $Path -ChildPath "OLEDLG.dll")) -eq $False) { - Write-CMLogEntry -Value "Copying OLEDLG.dll to $($Path) directory" -Severity 1 - if (([string]::IsNullOrEmpty($TSEnvironment.Value("OSDisk"))) -eq $false) { - IF (Test-Path -Path (Join-Path -path $TSEnvironment.Value("OSDisk") -ChildPath "Windows\System32\OLEDLG.dll")){ - Copy-Item -Path (Join-Path -path $TSEnvironment.Value("OSDisk") -ChildPath "Windows\System32\OLEDLG.dll") -Destination "$($Path)\OLEDLG.dll" - } - } - elseif ((Test-Path -Path "C:\Windows\System32\OLEDLG.dll") -eq $true) { - Copy-Item -Path "C:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" - } - elseif ((Test-Path -Path "D:\Windows\System32\OLEDLG.dll") -eq $true) { - Copy-Item -Path "D:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" - } - elseif ((Test-Path -Path "X:\Windows\System32\OLEDLG.dll") -eq $true) { - Copy-Item -Path "X:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" - } - else { - Write-CMLogEntry -Value "Failed to copy DLL file. Aborting update process" -Severity 3; exit 1 - } - } - - # WinUPTP bios upgrade utility file name - if (([Environment]::Is64BitOperatingSystem) -eq $true) { - $WinUPTPUtility = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "WinUPTP64.exe" } | Select-Object -ExpandProperty FullName - } - else { - $WinUPTPUtility = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "WinUPTP.exe" } | Select-Object -ExpandProperty FullName - } - + # Functions + function Write-CMLogEntry { + param ( + [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] + [ValidateNotNullOrEmpty()] + [string]$Value, + [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] + [ValidateNotNullOrEmpty()] + [ValidateSet("1", "2", "3")] + [string]$Severity, + [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] + [ValidateNotNullOrEmpty()] + [string]$FileName = "Invoke-LenovoBIOSUpdate.log" + ) + # Determine log file location + $LogFilePath = Join-Path -Path $Script:TSEnvironment.Value("_SMSTSLogPath") -ChildPath $FileName + + # Construct time stamp for log entry + $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), "+", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) + + # Construct date for log entry + $Date = (Get-Date -Format "MM-dd-yyyy") + + # Construct context for log entry + $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) + + # Construct final log entry + $LogText = "" + + # Add value to log file + try { + Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop + } + catch [System.Exception] { + Write-Warning -Message "Unable to append log entry to Invoke-LenovoBIOSUpdate.log file. Error message: $($_.Exception.Message)" + } + } + + Set-Location -Path $Path + # Write log file for script execution + Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for Lenovo BIOS updates" -Severity 1 + + # Check for required DLL's + if ((Test-Path -Path (Join-Path -Path $Path -ChildPath "OLEDLG.dll")) -eq $False) { + Write-CMLogEntry -Value "Copying OLEDLG.dll to $($Path) directory" -Severity 1 + if (([string]::IsNullOrEmpty($TSEnvironment.Value("OSDisk"))) -eq $false) { + Copy-Item -Path (Join-Path -Path $TSEnvironment.Value("OSDisk") -ChildPath "Windows\System32\OLEDLG.dll") -Destination "$($Path)\OLEDLG.dll" + } + elseif ((Test-Path -Path "C:\Windows\System32\OLEDLG.dll") -eq $true) { + Copy-Item -Path "C:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" + } + elseif ((Test-Path -Path "D:\Windows\System32\OLEDLG.dll") -eq $true) { + Copy-Item -Path "D:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" + } + elseif ((Test-Path -Path "X:\Windows\System32\OLEDLG.dll") -eq $true) { + Copy-Item -Path "X:\Windows\System32\OLEDLG.dll" -Destination "$($Path)\OLEDLG.dll" + } + else { + Write-CMLogEntry -Value "Failed to copy DLL file. Aborting update process" -Severity 3; exit 1 + } + } + + # WinUPTP bios upgrade utility file name # Flash CMD upgrade utility file name - if (([Environment]::Is64BitOperatingSystem) -eq $true) { - $FlashCMDUtility = Get-ChildItem -Path $Path -Filter "*.cmd" -Recurse | Where-Object { $_.Name -like "Flash64.cmd" } | Select-Object -ExpandProperty FullName + + switch ([Environment]::Is64BitOperatingSystem) { + $true { + $WinUPTPUtilityFilter = @('WinUPTP.exe', 'WinUPTP64.exe') + $FlashCMDUtilityFilter = @('Flash.cmd', 'Flash64.cmd') + } + $false { + $WinUPTPUtilityFilter = @('WinUPTP.exe') + $FlashCMDUtilityFilter = @('Flash.cmd') + } + } + + $WinUPTPUtilityFilter | ForEach-Object { + $PotentialWinUPTPUtility = Get-ChildItem -Path $Path -Filter $PSItem | Select-Object -ExpandProperty FullName + if ($PotentialWinUPTPUtility.Count -eq 1){ + $WinUPTPUtility = $PotentialWinUPTPUtility + } + } + + + $FlashCMDUtilityFilter | ForEach-Object { + $PotentialFlashCMDUtility = Get-ChildItem -Path $Path -Filter $PSItem | Select-Object -ExpandProperty FullName + if ($PotentialFlashCMDUtility.Count -eq 1){ + $FlashCMDUtility = $PotentialFlashCMDUtility + } + } + + + if ($WinUPTPUtility -ne $null) { + # Set required switches for silent upgrade of the bios and logging + Write-CMLogEntry -Value "Using WinUTPT BIOS update method" -Severity 1 + $FlashSwitches = " /S" + $FlashUtility = $WinUPTPUtility + } + + if ($FlashCMDUtility -ne $null) { + # Set required switches for silent upgrade of the bios and logging + Write-CMLogEntry -Value "Using FlashCMDUtility BIOS update method" -Severity 1 + $FlashSwitches = " /quiet /sccm /ign" + $FlashUtility = $FlashCMDUtility + } + + if (-not ($FlashUtility)) { + Write-CMLogEntry -Value "Supported upgrade utility was not found." -Severity 3; break + } + + if (-not ([System.String]::IsNullOrEmpty($Password))) { + # Add password to the flash bios switches + $FlashSwitches = $FlashSwitches + " /pass:$($Password)" + Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches -replace $Password, "")" -Severity 1 } else { - $FlashCMDUtility = Get-ChildItem -Path $Path -Filter "*.cmd" -Recurse | Where-Object { $_.Name -like "Flash.cmd" } | Select-Object -ExpandProperty FullName + Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches)" -Severity 1 } - if ($WinUPTPUtility -ne $null) { - # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using WinUTPT BIOS update method" -Severity 1 - $FlashSwitches = " /S" - $FlashUtility = $WinUPTPUtility - } - - if ($FlashCMDUtility -ne $null) { - # Set required switches for silent upgrade of the bios and logging - Write-CMLogEntry -Value "Using FlashCMDUtility BIOS update method" -Severity 1 - $FlashSwitches = " /quiet /sccm /ign" - $FlashUtility = $FlashCMDUtility - } - - if (-not($FlashUtility)) { - Write-CMLogEntry -Value "Supported upgrade utility was not found." -Severity 3; break - } - - if (-not([System.String]::IsNullOrEmpty($Password))) { - # Add password to the flash bios switches - $FlashSwitches = $FlashSwitches + " /pass:$($Password)" - Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches -replace $Password, "")" -Severity 1 - } - else { - Write-CMLogEntry -Value "Using the following switches for BIOS file: $($FlashSwitches)" -Severity 1 - } - - # Set log file location - $LogFilePath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName - - if (($TSEnvironment -ne $null) -and ($TSEnvironment.Value("_SMSTSinWinPE") -eq $true)) { - try { - # Start flash update process - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList "$FlashSwitches" -Passthru -Wait - - #Output Exit Code for testing purposes - $FlashProcess.ExitCode | Out-File -FilePath $LogFilePath - - #Get winuptp.log file - $WinUPTPLog = Get-ChildItem -Filter "*.log" -Recurse | Where-Object { $_.Name -like "winuptp.log" } -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName - if ($WinUPTPLog -ne $null) { - Write-CMLogEntry -Value "winuptp.log file path is $($WinUPTPLog)" -Severity 1 - $SMSTSLogPath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath "winuptp.log" - Copy-Item -Path $WinUPTPLog -Destination $SMSTSLogPath -Force -ErrorAction SilentlyContinue - } - } - catch [System.Exception] { - Write-CMLogEntry -Value "An error occured while updating the system BIOS in OS online phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 - } - } - else { - # Detect Bitlocker Status - $OSVolumeEncypted = if ((Manage-Bde -Status C:) -match "Protection On") { - Write-Output $True - } - else { - Write-Output $False - } - - # Supend Bitlocker if $OSVolumeEncypted is $true - if ($OSVolumeEncypted -eq $true) { - Write-CMLogEntry -Value "Suspending BitLocker protected volume: C:" -Severity 1 - Manage-Bde -Protectors -Disable C: - } - - # Start BIOS update process - try { - Write-CMLogEntry -Value "Running Flash Update - $($FlashUtility)" -Severity 1 - $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList "$($FlashSwitches)" -Passthru -Wait - - # Output Exit Code for testing purposes - $FlashProcess.ExitCode | Out-File -FilePath $LogFilePath - } - catch [System.Exception] - { - Write-Warning -Message "An error occured while updating the system bios. Error message: $($_.Exception.Message)"; exit 1 - } - } + # Set log file location + $LogFilePath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName + + if (($TSEnvironment -ne $null) -and ($TSEnvironment.Value("_SMSTSinWinPE") -eq $true)) { + try { + # Start flash update process + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList "$FlashSwitches" -PassThru -Wait + + #Output Exit Code for testing purposes + $FlashProcess.ExitCode | Out-File -FilePath $LogFilePath + + #Get winuptp.log file + $WinUPTPLog = Get-ChildItem -Filter "*.log" -Recurse | Where-Object { $_.Name -like "winuptp.log" } -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName + if ($WinUPTPLog -ne $null) { + Write-CMLogEntry -Value "winuptp.log file path is $($WinUPTPLog)" -Severity 1 + $SMSTSLogPath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath "winuptp.log" + Copy-Item -Path $WinUPTPLog -Destination $SMSTSLogPath -Force -ErrorAction SilentlyContinue + } + } + catch [System.Exception] { + Write-CMLogEntry -Value "An error occured while updating the system BIOS in OS online phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 + } + } + else { + # Detect Bitlocker Status + $OSVolumeEncypted = if ((Manage-Bde -Status C:) -match "Protection On") { + Write-Output $True + } + else { + Write-Output $False + } + + # Supend Bitlocker if $OSVolumeEncypted is $true + if ($OSVolumeEncypted -eq $true) { + Write-CMLogEntry -Value "Suspending BitLocker protected volume: C:" -Severity 1 + Manage-Bde -Protectors -Disable C: + } + + # Start BIOS update process + try { + Write-CMLogEntry -Value "Running Flash Update - $($FlashUtility)" -Severity 1 + $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList "$($FlashSwitches)" -PassThru -Wait + + # Output Exit Code for testing purposes + $FlashProcess.ExitCode | Out-File -FilePath $LogFilePath + } + catch [System.Exception] { + Write-Warning -Message "An error occured while updating the system bios. Error message: $($_.Exception.Message)"; exit 1 + } + } } From 0fe0dcb048ad67ab437ed97005f5a7ad6346a208 Mon Sep 17 00:00:00 2001 From: Stuart Adams <37147695+Stuart42@users.noreply.github.com> Date: Tue, 23 Aug 2022 11:19:29 -0300 Subject: [PATCH 14/14] Update Invoke-DellBIOSUpdate.ps1 Added missing /forceit switch for WinPE flash64 update --- Invoke-DellBIOSUpdate.ps1 | 103 +++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 36 deletions(-) diff --git a/Invoke-DellBIOSUpdate.ps1 b/Invoke-DellBIOSUpdate.ps1 index 01a7547..8fdf3b6 100644 --- a/Invoke-DellBIOSUpdate.ps1 +++ b/Invoke-DellBIOSUpdate.ps1 @@ -23,7 +23,7 @@ Contact: @modaly_it Created: 2017-05-30 Updated: 2022-07-22 - + Version history: 1.0.0 - (2017-05-30) Script created (Maurice Daly) 1.0.1 - (2017-06-01) Additional checks for both in OSD and normal OS environments (Maurice Daly) @@ -78,19 +78,19 @@ Process { ) # Determine log file location $LogFilePath = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $FileName - + # Construct time stamp for log entry $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), "+", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias)) - + # Construct date for log entry $Date = (Get-Date -Format "MM-dd-yyyy") - + # Construct context for log entry $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) - + # Construct final log entry $LogText = "" - + # Add value to log file try { Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop @@ -99,45 +99,45 @@ Process { Write-Warning -Message "Unable to append log entry to Invoke-DellBIOSUpdate.log file. Error message: $($_.Exception.Message)" } } - + # Default to task sequence variable set in detection script if (-not ([string]::IsNullOrEmpty($TSEnvironment.Value("OSDBIOSPackage01")))) { Write-CMLogEntry -Value "Using BIOS package location set in OSDBIOSPackage01 TS variable" -Severity 1 $Path = $TSEnvironment.Value("OSDBIOSPackage01") } - + # Run BIOS update process if BIOS package exists if (-not ([string]::IsNullOrEmpty($Path))) { - + # Write log file for script execution Write-CMLogEntry -Value "Initiating script to determine flashing capabilities for Dell BIOS updates" -Severity 1 - + # Flash BIOS upgrade utility file name $FlashUtility = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -like "Flash64W.exe" } | Select-Object -ExpandProperty FullName Write-CMLogEntry -Value "Attempting to use flash utility: $($FlashUtility)" -Severity 1 - + if ($FlashUtility -ne $null) { # Detect BIOS update executable $CurrentBIOSFile = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -notlike ($FlashUtility | Split-Path -Leaf) } | Select-Object -ExpandProperty FullName Write-CMLogEntry -Value "Attempting to use BIOS update file: $($CurrentBIOSFile)" -Severity 1 - + if ($CurrentBIOSFile -ne $null) { # Set log file location $BIOSLogFile = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName - + # Set required switches for silent upgrade of the bios and logging $FlashSwitches = "/b=$($CurrentBIOSFile) /s /l=$($BIOSLogFile)" # /forceit - + # Add password to the Flash64W.exe switches if ($PSBoundParameters["Password"]) { if (-not ([System.String]::IsNullOrEmpty($Password))) { $FlashSwitches = $FlashSwitches + " /p=$($Password)" } } - + if (($TSEnvironment -ne $null) -and ($TSEnvironment.Value("_SMSTSinWinPE") -eq $true)) { Write-CMLogEntry -Value "Current environment is determined as WinPE" -Severity 1 - + try { # Start flash update process if (-not ([System.String]::IsNullOrEmpty($Password))) { @@ -147,7 +147,7 @@ Process { Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches)" -Severity 1 } $FlashProcess = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop - + # Set reboot flag if restart required determined (exit code 2) @@ -163,7 +163,19 @@ Process { $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" } "10" { - Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3; exit 1 + Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3 #; exit 1 + $ResultsArray = (Get-Content $BIOSLogFile).Split(':') + if ($ResultsArray -like $BatteryError) { + Write-CMLogEntry -Value "Battery error detected (below 10%), adding /forceit switch and retrying" -Severity 2 + $FlashSwitches = $FlashSwitches + " /forceit" + $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + } + elseif ($ResultsArray -like $BatteryandPowerError) { + Write-CMLogEntry -Value "Battery error detected (no battery or power connection detected), adding /forceit switch and retrying" -Severity 2 + $FlashSwitches = $FlashSwitches + " /forceit" + $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + } + Write-CMLogEntry -Value "Laptop is on battery power. Retried the update with /forceit switch." -Severity 2; exit 1 } default { Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Please review the log file located at $($BIOSLogFile)" -Severity 3; exit 1 @@ -178,22 +190,24 @@ Process { else { # Used as a fall back for systems that do not support the Flash64w update tool # Used in a later section of the task sequence (after Setup Windows and ConfigMgr step) - + Write-CMLogEntry -Value "Current environment is determined as FullOS" -Severity 1 - + # Detect Bitlocker Status $OSVolumeEncypted = if ((Manage-Bde -Status C:) -match "Protection On") { Write-Output $true } else { Write-Output $false } - + # Supend Bitlocker if $OSVolumeEncypted is $true, remember to re-enable BitLocker after the flashing has occurred if ($OSVolumeEncypted -eq $true) { Write-CMLogEntry -Value "Suspending BitLocker protected volume: C:" -Severity 1 Manage-Bde -Protectors -Disable C: } - + # Start BIOS update process try { if (([Environment]::Is64BitOperatingSystem) -eq $true) { + $BatteryError = 'Error: The battery must be charged above 10% before the system BIOS can be flashed.' + $BatteryandPowerError = 'Error: The AC adapter and battery must be plugged in before the system BIOS can be flashed.' Write-CMLogEntry -Value "Starting 64-bit flash BIOS update process" -Severity 1 if (-not ([System.String]::IsNullOrEmpty($Password))) { Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches -replace $Password, "")" -Severity 1 @@ -201,7 +215,7 @@ Process { else { Write-CMLogEntry -Value "Using the following switches for $FlashUtility $($FlashSwitches)" -Severity 1 } - + # Update BIOS using Flash64W.exe $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop @@ -217,7 +231,19 @@ Process { $TSEnvironment.Value("SMSTSBIOSInOSUpdateRequired") = "False" } "10" { - Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3; exit 1 + Write-CMLogEntry -Value "Laptop is on battery power. The AC power must be connected to successfully flash the BIOS." -Severity 3#; exit 1 + $ResultsArray = (Get-Content $BIOSLogFile).Split(':') + if ($ResultsArray -like $BatteryError) { + Write-CMLogEntry -Value "Battery error detected (below 10%), adding /forceit switch and retrying" -Severity 2 + $FlashSwitches = $FlashSwitches + " /forceit" + $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + } + elseif ($ResultsArray -like $BatteryandPowerError) { + Write-CMLogEntry -Value "Battery error detected (no battery or power connection detected), adding /forceit switch and retrying" -Severity 2 + $FlashSwitches = $FlashSwitches + " /forceit" + $FlashUpdate = Start-Process -FilePath $FlashUtility -ArgumentList $FlashSwitches -PassThru -Wait -ErrorAction Stop + } + Write-CMLogEntry -Value "Laptop is on battery power. Retried the update with /forceit switch." -Severity 2; exit 1 } default { Write-CMLogEntry -Value "An error occured while updating the system BIOS during OS offline phase. Please review the log file located at $($BIOSLogFile)" -Severity 3; exit 1 @@ -227,14 +253,14 @@ Process { else { # Set required switches for silent upgrade of the BIOS $FileSwitches = " /l=$($BIOSLogFile) /s" - + # Add password to switches if ($PSBoundParameters["Password"]) { if (-not ([System.String]::IsNullOrEmpty($Password))) { $FileSwitches = $FileSwitches + " /p=$($Password)" } } - + Write-CMLogEntry -Value "Starting 32-bit flash BIOS update process" -Severity 1 if (-not ([System.String]::IsNullOrEmpty($Password))) { Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FlashSwitches -replace $Password, "")" -Severity 1 @@ -242,11 +268,11 @@ Process { else { Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FlashSwitches)" -Severity 1 } - + # Update BIOS using update file $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop } - + } catch [System.Exception] { Write-CMLogEntry -Value "An error occured while updating the system BIOS in OS online phase. Error message: $($_.Exception.Message)" -Severity 3; exit 1 @@ -259,24 +285,25 @@ Process { } else { $CurrentBIOSFile = Get-ChildItem -Path $Path -Filter "*.exe" -Recurse | Where-Object { $_.Name -match ".exe" } | Select-Object -ExpandProperty FullName - - Write-CMLogEntry -Value "Unable to locate the Flash64W.exe utility trying Manual Install" -Severity 1; + + Write-CMLogEntry -Value "Unable to locate the Flash64W.exe utility trying Manual Install" -Severity 1; # Set log file location $BIOSLogFile = Join-Path -Path $TSEnvironment.Value("_SMSTSLogPath") -ChildPath $LogFileName # Expected battery error for manual process $BatteryError = ' The battery must be charged above 10% before the system BIOS can be flashed.' - + $BatteryandPowerError = 'Error: The AC adapter and battery must be plugged in before the system BIOS can be flashed.' + # Set required switches for silent upgrade of the BIOS #$FileSwitches = "/s /r" $FileSwitches = "/s /l=$($BIOSLogFile)" - + # Add password to switches if ($PSBoundParameters["Password"]) { if (-not ([System.String]::IsNullOrEmpty($Password))) { $FileSwitches = $FileSwitches + " /p=$($Password)" } } - + Write-CMLogEntry -Value "Starting 32-bit flash BIOS update process" -Severity 1 if (-not ([System.String]::IsNullOrEmpty($Password))) { Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FileSwitches -replace $Password, "")" -Severity 1 @@ -284,16 +311,20 @@ Process { else { Write-CMLogEntry -Value "Using the following switches for BIOS file $CurrentBIOSFile : $($FileSwitches)" -Severity 1 Write-Host $FileSwitches - + } - + # Update BIOS using update file $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop if ($FileUpdate.ExitCode -eq 1) { $ResultsArray = (Get-Content $BIOSLogFile).Split(':') if ($ResultsArray -like $BatteryError) { - Write-CMLogEntry -Value "Battery error detected, adding /forceit switch and retrying" -Severity 2 + Write-CMLogEntry -Value "Battery error detected (below 10%), adding /forceit switch and retrying" -Severity 2 + $FileSwitches = $FileSwitches + " /forceit" + $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop + } elseif ($ResultsArray -like $BatteryandPowerError) { + Write-CMLogEntry -Value "Battery error detected (no battery or power connection detected), adding /forceit switch and retrying" -Severity 2 $FileSwitches = $FileSwitches + " /forceit" $FileUpdate = Start-Process -FilePath $CurrentBIOSFile -ArgumentList $FileSwitches -PassThru -Wait -ErrorAction Stop }