Advertisement
nullzilla

Task - Dell Command Update

May 11th, 2021 (edited)
4,336
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Import-Module $env:SyncroModule -DisableNameChecking
  2.  
  3. <# Requires Chocolatey or Syncro 3rd Party Patch Policy enabled
  4. Reboot disable switch doesn't seem to work 100%, so schedule after hours
  5. Some code borrowed from https://www.cyberdrain.com/monitoring-with-powershell-monitoring-dell-driver-updates-dcu-3-1/
  6.  
  7. 2024/5/7 - Updated with current version of Get-InstalledApps function and removal of Dell Update for Windows Universal
  8. 2024/7/9 - Added prerequisite check for workstation OS
  9.  
  10. TODO:
  11. failure catching
  12. add reboot conditions
  13. variablize update types/severity
  14. # # Disable schedule and notifications
  15. # &$dcu /configure -scheduleManual -updatesNotification=disable
  16. CLI Reference: https://www.dell.com/support/manuals/en-us/command-update/dellcommandupdate_rg/dell-command-|-update-cli-commands?guid=guid-92619086-5f7c-4a05-bce2-0d560c15e8ed&lang=en-us
  17. #>
  18.  
  19. $Reboot = $true
  20. $homepath = "c:\ICS" # Location to save report, DCU won't let us use Windows Temp or DCU folder
  21. $dcu = "${env:ProgramFiles}\Dell\CommandUpdate"
  22.  
  23. # Prerequisite checks
  24. if ((Get-CimInstance -ClassName Win32_ComputerSystem).Manufacturer -notlike 'Dell*') {
  25.     Write-Host "System Manufacturer is not Dell, exiting..."
  26.     exit 0
  27. }
  28. if ((Get-CimInstance Win32_OperatingSystem).ProductType -ne 1) {
  29.     Write-Host "Not a workstation OS, exiting..."
  30.     exit 0
  31. }
  32. if (-not (Test-Path "$homepath")) { mkdir "$homepath" | Out-Null }
  33. if (Test-Path "$env:SystemDrive\Program Files\RepairTech\Syncro\kabuto_app_manager\choco.exe") {
  34.     $choco = "$env:SystemDrive\Program Files\RepairTech\Syncro\kabuto_app_manager\choco.exe"
  35. } elseif (Test-Path "$env:AllUsersProfile\chocolatey\choco.exe") {
  36.     $choco = "$env:AllUsersProfile\chocolatey\choco.exe"
  37. } elseif ($env:ChocolateyInstall) {
  38.     $choco = $env:ChocolateyInstall
  39. } else {
  40.     Write-Host "Chocolatey not found, exiting..."
  41.     Rmm-Alert -Category "Dell Command Update" -Body "Chocolatey not found"
  42.     exit 1
  43. }
  44. $model = (Get-CimInstance -ClassName Win32_ComputerSystem).Model
  45. if ($model -notlike '*OptiPlex*' -and $model -notlike '*Latitude*' -and $model -notlike '*Precision*' -and $model -notlike '*Venue*' -and $model -notlike '*XPS*') {
  46.     Write-Host "Model not supported, installing Dell Update instead and exiting..."
  47.     &$choco upgrade dell-update -y --no-progress
  48.     exit 0
  49. }
  50.  
  51. # Uninstall no longer updated Chocolatey package (4.6), space at the end to avoid matching dellcommandupdate-uwp
  52. if ((&$choco list -local) -match "dellcommandupdate ") {
  53.     &$choco uninstall DellCommandUpdate -y --no-progress
  54. }
  55.  
  56. # Uninstall any remaining Dell Update applications
  57. $executable = $env:windir + "\system32\msiexec.exe"
  58. $AppsToRemove = @(
  59.     "Dell Command | Update"
  60.     "Dell Command | Update for Windows 10"
  61.     "Dell Update for Windows Universal"
  62. )
  63. function Get-InstalledApps {
  64.     # Modified from Test-InstalledSoftware function from https://github.com/darimm/RMMFunctions
  65.     $32BitPath = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
  66.     $64BitPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
  67.     # Empty array to store applications
  68.     $Apps = @()
  69.     # Retrieve globally installed applications
  70.     $Apps += Get-ItemProperty "HKLM:\$32BitPath" | Where-Object { $null -ne $_.DisplayName }
  71.     $Apps += Get-ItemProperty "HKLM:\$64BitPath" | Where-Object { $null -ne $_.DisplayName }
  72.     # Retrieve user profile applications
  73.     $AllProfiles = Get-CimInstance Win32_UserProfile |
  74.         Select-Object LocalPath, SID, Loaded, Special |
  75.             Where-Object { $_.SID -like "S-1-5-21-*" -or $_.SID -like "S-1-12-1-*" } # 5-21 regular users, 12-1 is AzureAD users
  76.     $MountedProfiles = $AllProfiles | Where-Object { $_.Loaded -eq $true }
  77.     $UnmountedProfiles = $AllProfiles | Where-Object { $_.Loaded -eq $false }
  78.     $MountedProfiles | ForEach-Object {
  79.         $Apps += Get-ItemProperty -Path "Registry::\HKEY_USERS\$($_.SID)\$32BitPath" | Where-Object { $null -ne $_.DisplayName }
  80.         $Apps += Get-ItemProperty -Path "Registry::\HKEY_USERS\$($_.SID)\$64BitPath" | Where-Object { $null -ne $_.DisplayName }
  81.     }
  82.     $UnmountedProfiles | ForEach-Object {
  83.         $Hive = "$($_.LocalPath)\NTUSER.DAT"
  84.         if (Test-Path $Hive) {
  85.             REG LOAD HKU\temp $Hive >$null
  86.             $Apps += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp\$32BitPath" | Where-Object { $null -ne $_.DisplayName }
  87.             $Apps += Get-ItemProperty -Path "Registry::\HKEY_USERS\temp\$64BitPath" | Where-Object { $null -ne $_.DisplayName }
  88.             # Run manual GC to allow hive to be unmounted
  89.             [GC]::Collect()
  90.             [GC]::WaitForPendingFinalizers()
  91.             REG UNLOAD HKU\temp >$null
  92.         }
  93.     }
  94.     return $Apps
  95. }
  96. foreach ($App in $AppsToRemove) {
  97.     Get-InstalledApps | Where-Object { $_.DisplayName -like "$App" -and $_.UninstallString -like "*MsiExec.exe*" } | ForEach-Object {
  98.         Write-Host "Uninstalling $($_.DisplayName)..." -NoNewline
  99.         $parameters = "/x " + $_.PSChildName + [char]32 + "/qn REBOOT=ReallySuppress /norestart"
  100.         $errCode = (Start-Process -FilePath $executable -ArgumentList $parameters -Wait -PassThru).ExitCode
  101.         If (($errCode -eq 0) -or ($errCode -eq 3010) -or ($errCode -eq 1605)) {
  102.             Write-Host "  Success"
  103.         } else {
  104.             Write-Host "  Failed with error code"$errCode
  105.         }
  106.     }
  107. }
  108.  
  109. # Install/Upgrade DCU
  110. if (-not (Test-Path "$dcu\DCU-CLI.exe")) {
  111.     # Force install used incase app was uninstalled without choco package being removed
  112.     &$choco install DellCommandUpdate-UWP -y -f --no-progress
  113.     if (-not (Test-Path "$dcu\DCU-CLI.exe")) {
  114.         Write-Host "DCU-CLI.exe not found, install failed, exiting..."
  115.         Rmm-Alert -Category "Dell Command Update" -Body "DCU-CLI.exe not found, install failed"
  116.         exit 1
  117.     }
  118. } else {
  119.     &$choco upgrade DellCommandUpdate-UWP -y --no-progress
  120. }
  121.  
  122. # Turn off notifications and scheduled scans
  123. &"$dcu\DCU-CLI.exe" /configure -scheduleManual -updatesNotification=disable
  124.  
  125. # See what updates are available
  126. &"$dcu\DCU-CLI.exe" /scan -report="$homepath"
  127.  
  128. # Exit Code 500 means no updates found
  129. if ($LastExitCode -eq 500) {
  130.     exit 0 # exit 0 so script doesn't fail
  131. }
  132.  
  133. [xml]$XMLReport = Get-Content "$homepath\DCUApplicableUpdates.xml"
  134. # Delete report because we don't need it anymore, and sometimes fails to overwrite
  135. Remove-Item "$homepath\DCUApplicableUpdates.xml" -Force
  136.  
  137. # Process report
  138. $AvailableUpdates = $XMLReport.updates.update
  139. $BIOSUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "BIOS" }).name.Count
  140. $ApplicationUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Application" }).name.Count
  141. $DriverUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Driver" }).name.Count
  142. $FirmwareUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Firmware" }).name.Count
  143. $OtherUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Other" }).name.Count
  144. $PatchUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Patch" }).name.Count
  145. $UtilityUpdates = ($AvailableUpdates | Where-Object { $_.type -eq "Utility" }).name.Count
  146. $RecommendedUpdates = ($AvailableUpdates | Where-Object { $_.Urgency -eq "Recommended" }).name.Count
  147. $UrgentUpdates = ($AvailableUpdates | Where-Object { $_.Urgency -eq "Urgent" }).name.Count
  148. $AvailableUpdates
  149. Write-Host "BIOS Updates: $BIOSUpdates"
  150. Write-Host "Application Updates: $ApplicationUpdates"
  151. Write-Host "Driver Updates: $DriverUpdates"
  152. Write-Host "Firmware Updates: $FirmwareUpdates"
  153. Write-Host "Other Updates: $OtherUpdates"
  154. Write-Host "Patch Updates: $PatchUpdates"
  155. Write-Host "Utility Updates: $UtilityUpdates"`n
  156. Write-Host "Recommended Updates: $RecommendedUpdates"
  157. Write-Host "Urgent Updates: $UrgentUpdates"
  158.  
  159. # Apply updates
  160. if ($AvailableUpdates) {
  161.     &"$dcu\DCU-CLI.exe" /ApplyUpdates -updateSeverity="Critical,Recommended" -AutoSuspendBitLocker=Enable -Reboot=Disable -ForceUpdate=Enable
  162.     if ($LastExitCode -eq 1) { # Exit Code 1 means a reboot is required
  163.         Write-Host "Reboot is required to finish updates."
  164.         if ($Reboot) {
  165.             "Reboot variable enabled, initiating reboot."
  166.             # If Automatic Restart Sign-On is enabled, the device automatically signs in and locks
  167.             # based on the last interactive user. After sign in, it restarts any registered applications.
  168.             shutdown /g /f
  169.             exit 0 # exit 0 so script doesn't fail
  170.         }
  171.     }
  172. }
  173.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement