Dell Driver Update Script

Most machines I support are Dell. I have been using Dell Support Assist to get driver updates done, but that’s slow and time consuming. SO, I’ve been looking into scripting the process. Dell Command Update has the ability to be run from PowerShell and I stumbled upon a script that seems to work, but I have to run it twice. I have rewritten a lot of the following script to make it work with Syncro, but note that I am not a scripting person.

This script will check if a Temp folder exists and if the Dell Command Update installer is present. I also altered it to check for if Dell Command Assist is already installed. After the checks, it will download and install Dell Command Update if it’s not already installed. Then, it’ll run a scan. The scan command and the update driver command are basically the same. This script will not install/update drivers currently, but all that would take is adding a line. I’ll add that command once I get this working better.

The problem: If the Temp folder and installer are not presant, the script will run all the way through, and error out when it comes time to read the XML file because it doesn’t seem to create it. However, the next time I run the script, it skips the download/install and just runs the scan, and then it works as intended. The output at the end and all the write-host commands are there for troubleshooting reasons.

I could split this up into 2 different scripts: 1) Install Dell Command Update and 2) Run Dell Command Assist, and it would work just fine. But, I’d like for it to be all in one script if possible.

$DownloadURL = "https://wolftech.cc/6516510615/DCU.EXE"
$DownloadLocation = "C:\Temp"

write-host "Download URL is set to $DownloadURL"
write-host "Download Location is set to $DownloadLocation"
 
$DCUExists = Test-Path "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe"
if (!$DCUExists) {
try {
    $TestDownloadLocation = Test-Path $DownloadLocation
    write-host "$DownloadLocation exists? $($TestDownloadLocation)"
    if (!$TestDownloadLocation) { new-item $DownloadLocation -ItemType Directory -force 
    write-host "Temp Folder has been created"}
    $TestDownloadLocationZip = Test-Path "$($DownloadLocation)\DellCommandUpdate.exe"
    write-host "DellCommandUpdate.exe exists? $($TestDownloadLocationZip)"
    if (!$TestDownloadLocationZip) { 
        write-host "Downloading DellCommandUpdate"
        Invoke-WebRequest -UseBasicParsing -Uri $DownloadURL -OutFile "$($DownloadLocation)\DellCommandUpdate.exe"
        write-host "Installing DellCommandUpdate..."
        Start-Process -FilePath "$($DownloadLocation)\DellCommandUpdate.exe" -ArgumentList "/s" -Wait
        write-host "DellCommandUpdate is now installed"
        set-service -name 'DellClientManagementService' -StartupType Manual 
        write-host "Just set DellClientManagmentService to Manual"
        
    }

    }
catch {
    write-host "The download and installation of DCUCli failed. Error: $($_.Exception.Message)"
    exit 1
}
}
write-host "Running a Scan..." 
Start-Process "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/scan -report=$($DownloadLocation)" -Wait
write-host "Scan Complete"
[ xml]$XMLReport = get-content "$DownloadLocation\DCUApplicableUpdates.xml"
#We now remove the item, because we don't need it anymore, and sometimes fails to overwrite
remove-item "$DownloadLocation\DCUApplicableUpdates.xml" -Force
 
$AvailableUpdates = $XMLReport.updates.update
 
$BIOSUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "BIOS" }).name.Count
$ApplicationUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Application" }).name.Count
$DriverUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Driver" }).name.Count
$FirmwareUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Firmware" }).name.Count
$OtherUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Other" }).name.Count
$PatchUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Patch" }).name.Count
$UtilityUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Utility" }).name.Count
$UrgentUpdates = ($XMLReport.updates.update | Where-Object { $_.Urgency -eq "Urgent" }).name.Count
write-host "Total Available Updates: $AvailableUpdates"
write-host "Bios Updates: $BIOSUpdates"
write-host "Application Updates: $ApplicationUpdates"
write-host "Driver Updates: $DriverUpdates"
write-host "Firmware Updates: $FirmwareUpdates"
write-host "Other Updates: $OtherUpdates"
write-host "Patch Updates: $PatchUpdates"
write-host "Utility Updates: $UtilityUpdates"
write-host "Urgent Updates: $UrgentUpdates"

(When Dell Command Update is not installed, and temp folder and is installer missing)
When I comment out the XML file delete command, I see that it’s not running the scan.

I am wondering if the script is not waiting for the install to complete, and it’s not running the scan command.

I use choco to install
choco upgrade dellcommandupdate

You need to start the DellClientManagementService service, and stop it after.

3 Likes

Figured out a way. I had to have the script wait a minute before running the DellCommandUpdate after it was installed.
Below is the new (functional script):

#This is to ensure that if an error happens, this script stops. 
$ErrorActionPreference = "Stop"

### Set your variables below this line ###
$DownloadURL = "https://wolftech.cc/6516510615/DCU.EXE"
$DownloadLocation = "C:\Temp"
$Reboot = "enable"
### Set your variables above this line ###

write-host "Download URL is set to $DownloadURL"
write-host "Download Location is set to $DownloadLocation"
 
#Check for 32bit or 64bit
$DCUExists32 = Test-Path "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe"
write-host "Does C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe exist? $DCUExists32"
$DCUExists64 = Test-Path "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe"
write-host "Does C:\Program Files\Dell\CommandUpdate\dcu-cli.exe exist? $DCUExists64"

if ($DCUExists32 -eq $true) {
    $DCUPath = "C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe"
}    
elseif ($DCUExists64 -eq $true) {
    $DCUPath = "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe"
}

if (!$DCUExists32 -And !$DCUExists64) {
    
        $TestDownloadLocation = Test-Path $DownloadLocation
        write-host "$DownloadLocation exists? $($TestDownloadLocation)"
        
        if (!$TestDownloadLocation) { new-item $DownloadLocation -ItemType Directory -force 
            write-host "Temp Folder has been created"
        }
        
        $TestDownloadLocationZip = Test-Path "$($DownloadLocation)\DellCommandUpdate.exe"
        write-host "DellCommandUpdate.exe exists in $($DownloadLocation)? $($TestDownloadLocationZip)"
        
        if (!$TestDownloadLocationZip) { 
            write-host "Downloading DellCommandUpdate..."
            Invoke-WebRequest -UseBasicParsing -Uri $DownloadURL -OutFile "$($DownloadLocation)\DellCommandUpdate.exe"
            write-host "Installing DellCommandUpdate..."
            Start-Process -FilePath "$($DownloadLocation)\DellCommandUpdate.exe" -ArgumentList "/s" -Wait
            $DCUExists = Test-Path "$($DCUPath)"
            write-host "Done. Does $DCUPath exist now? $DCUExists"
            set-service -name 'DellClientManagementService' -StartupType Manual 
            write-host "Just set DellClientManagmentService to Manual"  
        }
}
    


$DCUExists = Test-Path "$DCUPath"
write-host "About to run $DCUPath. Lets be sure to be sure. Does it exist? $DCUExists"

Start-Process "$($DCUPath)" -ArgumentList "/scan -report=$($DownloadLocation)" -Wait
write-host "Checking for results."


$XMLExists = Test-Path "$DownloadLocation\DCUApplicableUpdates.xml"
if (!$XMLExists) {
        write-host "Something went wrong. Waiting 60 seconds then trying again..."
     Start-Sleep -s 60
    Start-Process "$($DCUPath)" -ArgumentList "/scan -report=$($DownloadLocation)" -Wait
    $XMLExists = Test-Path "$DownloadLocation\DCUApplicableUpdates.xml"
    write-host "Did the scan work this time? $XMLExists"
}
if ($XMLExists -eq $true) {
    [xml]$XMLReport = get-content "$DownloadLocation\DCUApplicableUpdates.xml"
    $AvailableUpdates = $XMLReport.updates.update
     
    $BIOSUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "BIOS" }).name.Count
    $ApplicationUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Application" }).name.Count
    $DriverUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Driver" }).name.Count
    $FirmwareUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Firmware" }).name.Count
    $OtherUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Other" }).name.Count
    $PatchUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Patch" }).name.Count
    $UtilityUpdates = ($XMLReport.updates.update | Where-Object { $_.type -eq "Utility" }).name.Count
    $UrgentUpdates = ($XMLReport.updates.update | Where-Object { $_.Urgency -eq "Urgent" }).name.Count
    
    #Print Results
    write-host "Bios Updates: $BIOSUpdates"
    write-host "Application Updates: $ApplicationUpdates"
    write-host "Driver Updates: $DriverUpdates"
    write-host "Firmware Updates: $FirmwareUpdates"
    write-host "Other Updates: $OtherUpdates"
    write-host "Patch Updates: $PatchUpdates"
    write-host "Utility Updates: $UtilityUpdates"
    write-host "Urgent Updates: $UrgentUpdates"
}

if (!$XMLExists) {
    write-host "We tried again and the scan still didn't run. Not sure what the problem is, but if you run the script again it'll probably work."
    exit 1
}
else {
    #We now remove the item, because we don't need it anymore, and sometimes fails to overwrite
    remove-item "$DownloadLocation\DCUApplicableUpdates.xml" -Force    
}
$Result = $BIOSUpdates + $ApplicationUpdates + $DriverUpdates + $FirmwareUpdates + $OtherUpdates + $PatchUpdates + $UtilityUpdates + $UrgentUpdates
write-host "Total Updates Available: $Result"
if ($Result -gt 0) {

    $OPLogExists = Test-Path "$DownloadLocation\updateOutput.log"
    if ($OPLogExists -eq $true) {
        remove-item "$DownloadLocation\updateOutput.log" -Force
    }

    write-host "Lets do it! Updating Drivers. This may take a while..."
    Start-Process "$($DCUPath)" -ArgumentList "/applyUpdates -autoSuspendBitLocker=enable -reboot=$($Reboot) -outputLog=$($DownloadLocation)\updateOutput.log" -Wait
    Start-Sleep -s 60
    Get-Content -Path '$DownloadLocation\updateOutput.log'
    write-host "Done."
    exit 0
}

Problem with this one, is if a different version of DellCommandUpdate or Dell Update is installed, it’ll fail.
Looks like I am going to have to write in removal of incompatible versions.

1 Like

I’ll look into that, thanks!

Here’s mine. Task - Dell Command Update - Pastebin.com I use standalone chocolatey, but you could point at the Syncro one instead if you want.

1 Like

Sweet thanks! Tons of good ideas in this one.

Do any of these scripts suspend Bitlocker so the user does not have to enter the recovery code on reboot?

Recent versions do so automatically, but yes I specifically enabled it in my script to be sure.

Awesome thanks for sharing that.

I’d make it two scripts. One for the install, and do that as part of your onboarding a device, and separate script to run the updates.

Yes, this is done with the -autoSuspendBitLocker=enable flag

Yeah, I see that this is probably the best way to go about it. Often times the DCU requires a reboot if it hadn’t been updated in a while, SO, that bit has to be done after hours.

1 Like

@isaacg Hey, I am using your script to run Dell Command Update but am having some issues.

I am getting an error when I am trying to uninstall the existing app, which is the UWP version. Here is what I am seeing:

Remove-AppxPackage : Removal failed. Please contact your software vendor.

Deployment DeStage operation with target volume C: on Package DellInc.DellCommandUpdate_4.4.18.0_x86__htrsf667h5kn2 from: failed with error 0x80070002. See
Troubleshooting packaging, deployment, and query of Windows apps - Win32 apps | Microsoft Docs for help diagnosing app deployment issues.
At C:\ProgramData\Syncro\bin\fa99913d-2ea2-4fb7-a01e-5e0900772a4a.ps1:35 char:12

  • $app | Remove-AppxPackage -allusers
    
  •        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Remove-AppxPackage], COMException
    • FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.Windows.Appx.PackageManager.Commands.RemoveAppxPackageCommand

If I manually remove the app then run your script after, it works and installed the x86 version and finishes the script.

For some reason it doesn’t like to uninstall with the script.

Any ideas?

I revamped the uninstall to work on application name instead of hardcoded MSI GUID so it will be more robust now: Task - Dell Command Update - Pastebin.com