Skip to main content

Disclaimer - this will apply all Dell driver updates without a reboot. It is up to you to configure this to your environment.



This worklet will Install Dell Command Update. Be sure to include the binaries and update the name to the EXE you use. https://www.dell.com/support/home/en-us/drivers/DriversDetails?driverId=JDXHH



Once installed or if already installed the worklet is setup to install updates then parse through a log to provide some details on what updates, if any were installed.





Activity Log Output



image





Evaluation Code



$system = Get-WmiObject win32_computersystem

IF($system.Manufacturer -match "Dell"){ Exit 1 }else { Exit 0 }





Remediation Code



# Dell Command | Update executable uploaded to worklet

$exe = 'Dell-Command-Update-Application-for-Windows10_JDXHH_WIN_4.2.0_A00.EXE'



# Dell Command Version

[version]$version = '4.2.0'



# Log location

$log = 'C:\Windows\Temp\DellCommand_Install.txt'



$system = Get-WmiObject win32_computersystem

IF($system.Manufacturer -match "Dell"){



# Find versions of Dell Command installed

$scriptblock = {

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where DisplayName -match 'Dell Command'

}

# Run the scriptblock and store results in the $64bit variable

$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock



function Install-DellCommand{

[void](Start-Process -FilePath $exe -ArgumentList "/s /l='$log'" -wait -PassThru)

IF($? -eq "True"){

return $true

}else{

return $false

}



Start-Sleep -Seconds 20

# Configure Dell Command Update

Write-Host

$Arguments = 'scheduleAuto',

'lockSettings=enable',

'userConsent=disable',

'scheduleMonthly=28,00:45',

'scheduledReboot=0',

'autoSuspendBitLocker=enable'

foreach ($Arg in $Arguments){

$results = Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/configure -$Arg" -Wait | Out-Null

Start-Sleep -Seconds 5

}

}



# IF Dell Command is not installed or older version exists

IF(!$software){

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}else{

# Remove older versions of Dell Command

foreach ($title in $software){

IF([version]$title.DisplayVersion -lt $version){

Write-Output "Uninstall Dell Command $($title.DisplayVersion). "

$UninstallString = $title.UninstallString | Select-String -Pattern '{[-0-9A-F]+?}' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value

Start-Process MsiExec -ArgumentList "/X $UninstallString /qn" -Wait

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}

}

}



# Apply Updates

Function Start-DellCommandUpdates {

# 2 minute timeout if dcu-cli is already running

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){

Write-Output "dcu-cli currently running. Wait for process to complete. "

$startDate = Get-Date

do{}while((Get-Process dcu-cli -ea SilentlyContinue) -and $startDate.AddMinutes(2) -gt (Get-Date))

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){Stop-Process dcu-cli -Force}

}

# Run dcu-cli

Write-Output "Starting Dell Command Update Process. "

Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/applyUpdates" -Wait

}

Start-DellCommandUpdates



# Get Activity

Function Get-DellCommandActivity {

# Get Activity Log and parse intalled updates in last 24 hours

[xml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\Activity.log"

$range = (Get-Date).AddHours(-24)

# Write output on Checking Updates

$events = $a.LogEntries.LogEntry | Select timestamp,message | where {[datetime]$_.timestamp -gt $range -and ($_.message -match 'found' -or $_.message -match 'Checking for updates' -or $_.message -match 'verified')} | % {

$timestamp = (Get-Date $_.timestamp -Format 'yyyy-MM-dd hh:mm tt')

$message = $_.message.replace(' verified.','')

[pscustomobject] @{

timestamp = $timestamp

message = $message

}

}

foreach ($event in $events)

{

Write-Output "$($event.timestamp) $($event.message). "

}

}

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

Write-Output "Something went wrong. Trying to run Dell Command Update again. "

Get-Process dcu-cli -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force

Start-DellCommandUpdates

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

IF(Test-Path 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'){

Write-Output "Something isn't working right. Recommend running this locally and analyzing output: 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe' /applyUpdates "

Write-Output $activity

}else{Write-Output "Dell Command failed to install. "}

}

}

}else{Write-Host "Not recognized as Dell Manufacturer. Not running." }

highly recommend starting with the latest version 4.2 as to not introduce a vulnerability into the environment https://www.dell.com/support/kbdoc/en-us/000186019/dsa-2021-088-dell-client-platform-security-update-for-dell-driver-insufficient-access-control-vulnerability


Good callout on considering a newer version of Dell Command. Looks like hot off the press too! I will get that link updated above.



What is really cool is using this worklet “should” also update the version of Dell Command when dcu-cli.exe /applyUpdates is used. Here is an example of that happening in the activity log.


image



My understanding is Dell Command plays a role in dropping the dbutil_2_3.sys file. Did you find something where 4.2 prevents that from happening? To buy some time to get the firmware patched I’m using this worklet-- CVE-2021-21551 Band-Aid Dell BIOS Driver Privilege Escalation Flaws - #5 by Tony


Hi Jack,



Thank you for the update! If I upload the new 4.2 version it’s fine? it is a silent install?



It does not install Dell command first, can you please let me know how I can create a seperate policy just for installation?



Thanks,


Omid


Thanks for the heads up @OROR



I’ve updated the remediation code above to correct not installing Dell Command.



If you want a separate policy just for installation you could try this –



#Evaluation



$system = Get-WmiObject win32_computersystem

IF($system.Manufacturer -match "Dell"){

# Find versions of Dell Command installed

$scriptblock = {

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where DisplayName -match 'Dell Command'

}

# Run the scriptblock and store results in the $64bit variable

$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock



# IF Dell Command is not installed or older version exists

IF($software -eq ''){ Exit 1 }else{ Exit 0 }

}else{exit 0}





Remediation



 # Dell Command | Update executable uploaded to worklet

$exe = 'Dell-Command-Update-Application-for-Windows10_JDXHH_WIN_4.2.0_A00.EXE'



# Dell Command Version

version]$version = '4.2.0'



# Log location

$log = 'C:\Windows\Temp\DellCommand_Install.txt'



$system = Get-WmiObject win32_computersystem

IF($system.Manufacturer -match "Dell"){



# Find versions of Dell Command installed

$scriptblock = {

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where DisplayName -match 'Dell Command'

}

# Run the scriptblock and store results in the $64bit variable

$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock



function Install-DellCommand{

void](Start-Process -FilePath $exe -ArgumentList "/s /l='$log'" -wait -PassThru)

IF($? -eq "True"){

return $true

}else{

return $false

}



Start-Sleep -Seconds 20

# Configure Dell Command Update

Write-Host

$Arguments = 'scheduleAuto',

'lockSettings=enable',

'userConsent=disable',

'scheduleMonthly=28,00:45',

'scheduledReboot=0',

'autoSuspendBitLocker=enable'

foreach ($Arg in $Arguments){

$results = Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/configure -$Arg" -Wait | Out-Null

Start-Sleep -Seconds 5

}

}



# IF Dell Command is not installed or older version exists

IF(!$software){

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}else{

# Remove older versions of Dell Command

foreach ($title in $software){

IF( version]$title.DisplayVersion -lt $version){

Write-Output "Uninstall Dell Command $($title.DisplayVersion). "

$UninstallString = $title.UninstallString | Select-String -Pattern '{n-0-9A-F]+?}' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value

Start-Process MsiExec -ArgumentList "/X $UninstallString /qn" -Wait

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}

}

}



# Apply Updates

Function Start-DellCommandUpdates {

# 2 minute timeout if dcu-cli is already running

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){

Write-Output "dcu-cli currently running. Wait for process to complete. "

$startDate = Get-Date

do{}while((Get-Process dcu-cli -ea SilentlyContinue) -and $startDate.AddMinutes(2) -gt (Get-Date))

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){Stop-Process dcu-cli -Force}

}

# Run dcu-cli

Write-Output "Starting Dell Command Update Process. "

Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/applyUpdates" -Wait

}

Start-DellCommandUpdates



# Get Activity

Function Get-DellCommandActivity {

# Get Activity Log and parse intalled updates in last 24 hours

xml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\Activity.log"

$range = (Get-Date).AddHours(-24)

# Write output on Checking Updates

$events = $a.LogEntries.LogEntry | Select timestamp,message | where {rdatetime]$_.timestamp -gt $range -and ($_.message -match 'found' -or $_.message -match 'Checking for updates' -or $_.message -match 'verified')} | % {

$timestamp = (Get-Date $_.timestamp -Format 'yyyy-MM-dd hh:mm tt')

$message = $_.message.replace(' verified.','')

pscustomobject] @{

timestamp = $timestamp

message = $message

}

}

foreach ($event in $events)

{

Write-Output "$($event.timestamp) $($event.message). "

}

}

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

Write-Output "Something went wrong. Trying to run Dell Command Update again. "

Get-Process dcu-cli -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force

Start-DellCommandUpdates

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

IF(Test-Path 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'){

Write-Output "Something isn't working right. Recommend running this locally and analyzing output: 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe' /applyUpdates "

Write-Output $activity

}else{Write-Output "Dell Command failed to install. "}

}

}

}else{Write-Host "Not recognized as Dell Manufacturer. Not running." }

Hello Jack please test, it does not work for me but I could install the 4.2 version with this simple script:



 $proc = Start-Process -filepath ".\Dell-Command-Update-Application-for-Windows10_JDXHH_WIN_4.2.0_A00.EXE" -ArgumentList "/s /f /l='C:\Windows\Temp\Spreetail_MDT_DellCommand_Install.txt'" -wait -PassThru

Write-Output "Exit Code was $($proc.ExitCode)"

Exit $proc.ExitCode

In your original script when it runs Dell command there is pop up windows and users need to click “OK” when it gets to this line:



$results = Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/configure -$Arg" -Wait | Out-Null



Do you know how I can force it to run automatically without users involved?



Thanks,


Omid


Interesting. I’m not sure how to reproduce that. Do you have other Dell Command products installed perhaps?




@OROR got it. swapped out



($software -eq '')



for


(!$software)


Sorry, my bad I was tested directly from powershell if you push it though automox there is not pop up! 🙂


Can you assist with adding in IF the workstation has “Dell Command | Update for Windows 10” installed, to remove it and install “Dell Command | Update”



“Dell Command | Update for Windows 10” is the universal version and it won’t update or install this version if that version is installed on the computer. Also the universal version doesn’t allow for scripts to be run to initiate silent updates etc.



Thank you in advance. The provided script works great otherwise!


Also, using the remediation script you provided in the original post…the updates aren’t being carried out.



This is what i receive in the Activity log. However when i run Dell Command manually, there are several updates, including critical, recommended and optional.






Installing Dell Command. Installed Dell Command. Starting Dell Command Update Process. 2021-06-06 02:10 PM Checking for updates. 2021-06-06 03:07 PM found u0] updates. 2021-06-07 11:40 AM found u0] updates. 2021-06-07 11:40 AM found u0] updates.


@jcropanese



Thinking you could accomplish that with this snippet of code



# Find versions of Dell Command installed

$scriptblock = {

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where DisplayName -match 'Dell Command'

}

# Run the scriptblock and store results in the $64bit variable

$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock



IF([version]$software.DisplayName -eq 'Dell Command | Update for Windows 10'){

Write-Output "Uninstall Dell Command $($software.DisplayVersion). "

$UninstallString = $software.UninstallString | Select-String -Pattern '{[-0-9A-F]+?}' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value

Start-Process MsiExec -ArgumentList "/X $UninstallString /qn" -Wait

}



The output is parsing XML from Dell Command after running dcu-clie.exe /applyupdates. Perhaps Dell Command is not configured as expected? You can look with this.



& 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe' /configure -exportSettings=C:\temp

Sorry i am very new to powershell and am working through your script, so i apologize. This is helping me tremendously and will help with my other scripts too, so thank you!



From my understanding, the snippet you provided will look for ANY version of the software named ‘Dell Command | Update for Windows 10’ and uninstall it … correct?



So what i am looking to accomplish in my script is combing both that and what you originally provided.



So i want it to remove the ‘Dell Command | Update for Windows 10’ if it exists and then install the correct one otherwise just install the correct one. Can you show me what the final code would look like?



Thank you for helping!




Can you help me understand the difference between “Dell Command | Update” and “Dell Command | Update for Windows 10”. When I install the binaries linked in the original post, it shows up in Programs and Features as “Dell Command | Update for Windows 10”. By adding that logic to the entire code the solution would uninstall/install Dell Command every time it runs. I’m curious if there is something else that differentiates the difference between the two.


So there are 2 versions, the one you have in your script with " Dell Command | Update for Windows 10 " is the universal app and the other one I am referring to is the normal app and just shows up as “Dell Command | Update” . I have a mixture of the 2 in my environment and would like to just have the normal one installed, so trying to incorporate the uninstall of the other and install of the new into the script .



I had read an article not long ago that there was something wrong with CLI on the universal app, but maybe it is fixed now. In either case, I’d like to just get one version of the app on all machines.




You are correct. The original script is looking for ANY version that is a match of DisplayName “Dell Command” which would include both application titles. Really appreciate you for pointing that out as up until now didn’t even realize two versions existed.



https://www.dell.com/support/kbdoc/en-us/000177325/dell-command-update





To your other ask. This code will follow the same logic as above. Removing any version less than 4.2 as well as versions of “Dell Command | Update for Windows 10”.



# Dell Command | Update executable uploaded to worklet

$exe = 'Dell-Command-Update-Application_MJ3C3_WIN_4.2.0_A00.EXE'



# Dell Command Version

oversion]$version = '4.2.0'



# Log location

$log = 'C:\Windows\Temp\DellCommand_Install.txt'



$system = Get-WmiObject win32_computersystem

IF($system.Manufacturer -match "Dell"){



# Find versions of Dell Command installed

$scriptblock = {

Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where DisplayName -match 'Dell Command'

}

# Run the scriptblock and store results in the $64bit variable

$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock



function Install-DellCommand{


IF($? -eq "True"){

return $true

}else{

return $false

}



Start-Sleep -Seconds 20

# Configure Dell Command Update

Write-Host

$Arguments = 'restoreDefaults',

'scheduleAuto',

'lockSettings=enable',

'userConsent=disable',

'scheduleMonthly=28,00:45',

'scheduledReboot=0',

'autoSuspendBitLocker=enable'

foreach ($Arg in $Arguments){

$results = Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/configure -$Arg" -Wait | Out-Null

Start-Sleep -Seconds 5

}

}



# IF Dell Command is not installed or older version exists

IF(!$software){

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}else{

# Remove older versions of Dell Command

foreach ($title in $software){

IF( version]$title.DisplayVersion -lt $version -or $title.Displayname -eq "Dell Command | Update for Windows 10"){

Write-Output "Uninstall $($title.Displayname) version $($title.DisplayVersion). "

$UninstallString = $title.UninstallString | Select-String -Pattern '{i-0-9A-F]+?}' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value

Start-Process MsiExec -ArgumentList "/X $UninstallString /qn" -Wait



$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock

IF(!$software){

Write-Output "Installing Dell Command. "

IF(Install-DellCommand){Write-Output "Installed Dell Command. "}else{Write-Output "Failed to install Dell Command. "; exit 1}

}else{Write-Output "Detected $($software.DisplayName) version $($software.DisplayVersion). "}

}

}

}



# Apply Updates

Function Start-DellCommandUpdates {

# 2 minute timeout if dcu-cli is already running

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){

Write-Output "dcu-cli currently running. Wait for process to complete. "

$startDate = Get-Date

do{}while((Get-Process dcu-cli -ea SilentlyContinue) -and $startDate.AddMinutes(2) -gt (Get-Date))

$dcu = Get-Process dcu-cli -ErrorAction SilentlyContinue

IF($dcu){Stop-Process dcu-cli -Force}

}

# Run dcu-cli

Write-Output "Starting Dell Command Update Process. "

Start-Process -FilePath "C:\Program Files\Dell\CommandUpdate\dcu-cli.exe" -ArgumentList "/applyUpdates" -Wait

}

Start-DellCommandUpdates



# Get Activity

Function Get-DellCommandActivity {

# Get Activity Log and parse intalled updates in last 24 hours


$range = (Get-Date).AddHours(-24)

# Write output on Checking Updates

$events = $a.LogEntries.LogEntry | Select timestamp,message | where {sdatetime]$_.timestamp -gt $range -and ($_.message -match 'found' -or $_.message -match 'Checking for updates' -or $_.message -match 'verified')} | % {

$timestamp = (Get-Date $_.timestamp -Format 'yyyy-MM-dd hh:mm tt')

$message = $_.message.replace(' verified.','')

/pscustomobject] @{

timestamp = $timestamp

message = $message

}

}

foreach ($event in $events)

{

Write-Output "$($event.timestamp) $($event.message). "

}

}

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

Write-Output "Something went wrong. Trying to run Dell Command Update again. "

Get-Process dcu-cli -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force

Start-DellCommandUpdates

$activity = Get-DellCommandActivity

foreach ($event in $activity){

Write-Output "$event"

}

IF($activity.count -eq 0){

IF(Test-Path 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'){

Write-Output "Something isn't working right. Recommend running this locally and analyzing output: 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe' /applyUpdates "

Write-Output $activity

}else{Write-Output "Dell Command failed to install. "}

}

}

}else{Write-Host "Not recognized as Dell Manufacturer. Not running." }

With that script, it’s not removing the Universal one from my test computer.



When looking at your script, how is $title defined? I’ve been starring at this script for a while and starting to lose track as to what each part is doing. HAHA




$software is a variable that could collect multiple objects. For example if you had ‘Dell Command | Update’ and ‘Dell Command | Update for Windows 10’ installed at the same time. In this case $title becomes the ONE object being looked at at the time of the for each loop. You could rename $title to almost anything you want.



ForEach($title in $software)


Reply