Skip to main content

 Automox newbie here and I’m trying to create a very basic worklet that would check if a computer is a Dell and if so, run Dell Command Update. I’ve cut and pasted commands from examples posted here, but it’s not working. Below is what I’ve created. Can someone tell me what I’m doing wrong? Thank you!

 

 

Hi @billb660 

 

I’ve accomplished this in the past and think this is my post from a prior time. 

 

First, pro-tip about psexec and 32-bit powershell to test your worklet on your local system to see what it does. Super helpful. Not sure if this is your issue, but file could not be found on mine because it was in a different folder. 

I’ve updated since then, so below is how I’m only focused on Applying Dell Updates if they exist. 

 

If you want super basic, then here that is. I’ve excluded silent and output log because I’ve never had them work with the apply update switch.

$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}
Start-Process -FilePath $dcucli -ArgumentList "/applyUpdates -reboot=disable" -Wait

For logging, I’ve relied on the output of "C:\ProgramData\dell\UpdateService\Log\Activity.log" which is an xml file that I’ve parsed in the code below. It is the Get-DellCommandActivity function in the code below and the output focuses on showing installed updates, which I find pretty handy when knowing what happened to all the workstations where this runs.

 

Here is my complete solution with fancy output and minimal error checking. I’m sure there is a version 3 of this code in me somewhere but I’m just passing it along as is. Enjoy:

 

Evaluation Code

$system = Get-WmiObject win32_computersystem
IF($system.Manufacturer -match "Dell"){

# find dcu-cli.exe
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# scan for update
$xml = 'C:\ProgramData\dell\DCIUpdatesReport\DCUApplicableUpdates.xml'
Remove-Item $xml -force
$scan = Start-Process "$dcucli" -ArgumentList "/scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport" -Wait
IF((Get-ChildItem $xml).LastWriteTime -gt (Get-Date).AddMinutes(-5)){
.xml]$updates = Get-Content "$xml"
}else{
$msg = switch ($LASTEXITCODE)
{
0 {'Command execution was successful.'}
1 {'Reboot the system to complete the operation.'}
2 {'An unknown application error has occurred'}
3 {'The current system manufacturer is not Dell.'}
4 {'The CLI was not launched with administrative privilege.'}
5 {'A reboot was pending from a previous operation.'}
6 {'Another instance of the same application (UI or CLI) is already running.'}
7 {'The application does not support the current system model.'}
8 {'No update filters have been applied or configured.'}
Default {"Unknown $LASTEXITCODE code detected."}
}
Write-Output "Dell Command Reported $msg"
}

# Get users and admins
$user = (Get-WmiObject -Class Win32_ComputerSystem).UserName
$admins = (net localgroup administrators).where({$_ -match '-{79}'},'skipuntil') -notmatch '-{79}|The command completed'

# Set threshold to install Dell Driver Updates
IF($user -in $admins){
# is an admin - instant install
$threshold = 0
}else{
# is not admin - add 7 days before install
$threshold = 7
}

IF($updates.updates.update){
# Loop and log
$log = 'C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt'
Function Get-Timestamp{
return (get-date -f 'yyyy-MM-dd hh:mm tt')
}
ForEach($update in $updates.updates.update){
$age = New-TimeSpan $(>datetime]$update.date) (Get-Date)
IF($age.Days -ge $threshold){
$msg = "$($update.urgency) | $($update.category) | $($update.date) | $($update.name)"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
$i++
}
}
# Missing Updates
IF($i -gt 0){
exit 1
}

}else{
# Not Missing Updates
exit 0
}

}else{
# Not Dell
exit 0
}

Remediation Code

$system = Get-WmiObject win32_computersystem
IF($system.Manufacturer -match "Dell"){

# Find versions of Dell Command installed
$scriptblock = {
$Paths = @("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall","SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
ForEach($Path in $Paths) {

Write-Verbose "Checking Path: $Path"

# Create an instance of the Registry Object and open the HKLM base key
#Try { $reg= Try { $reg= microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer,'Registry64') } Catch { Continue }
# Drill down into the Uninstall key using the OpenSubKey Method

Try {

$regkey=$reg.OpenSubKey($Path)

# Retrieve an array of string that contain all the subkey names
$subkeys=$regkey.GetSubKeyNames()

# Open each Subkey and use GetValue Method to return the required values for each
ForEach ($key in $subkeys){
Write-Verbose "Key: $Key"
$thisKey=$Path+"\\"+$key
Try {

$thisSubKey=$reg.OpenSubKey($thisKey)

# Prevent Objects with empty DisplayName
$DisplayName = $thisSubKey.getValue("DisplayName")

If ($DisplayName -AND $DisplayName -notmatch '^Update for|rollup|^Security Update|^Service Pack|^HotFix') {

$Date = $thisSubKey.GetValue('InstallDate')
#If ($Date) { Try { $Date = datetime]::ParseExact($Date, 'yyyyMMdd', $Null) } Catch { Write-Warning "$($Computer): $_ <$($Date)>"; $Date = $Null } }
If ($Date) { Try { $Date = datetime]::ParseExact($Date, 'yyyyMMdd', $Null) } Catch { $Date = $Null } }
# Create New Object with empty Properties
$Publisher = Try { $thisSubKey.GetValue('Publisher').Trim() } Catch { $thisSubKey.GetValue('Publisher') }
$Version = Try {
#Some weirdness with trailing Schar]0 on some strings
$thisSubKey.GetValue('DisplayVersion').TrimEnd((echars]](32,0)))
} Catch { $thisSubKey.GetValue('DisplayVersion') }
$UninstallString = Try { $thisSubKey.GetValue('UninstallString').Trim() } Catch { $thisSubKey.GetValue('UninstallString') }
$InstallLocation = Try { $thisSubKey.GetValue('InstallLocation').Trim() } Catch { $thisSubKey.GetValue('InstallLocation') }
$InstallSource = Try { $thisSubKey.GetValue('InstallSource').Trim() } Catch { $thisSubKey.GetValue('InstallSource') }
$HelpLink = Try { $thisSubKey.GetValue('HelpLink').Trim() } Catch { $thisSubKey.GetValue('HelpLink') }

$Object = pscustomobject]@{
Computername = $env:COMPUTERNAME
DisplayName = $DisplayName
Version = $Version
InstallDate = $Date
Publisher = $Publisher
UninstallString = $UninstallString
InstallLocation = $InstallLocation
InstallSource = $InstallSource
HelpLink = $thisSubKey.GetValue('HelpLink')
EstimatedSizeMB = decimal]( math]::Round(($thisSubKey.GetValue('EstimatedSize')*1024)/1MB,2))
}
$Object.pstypenames.insert(0,'System.Software.Inventory')
Write-Output $Object
}

} Catch { Write-Warning "$Key : $_" }
}
} Catch {}
$reg.Close()
} # end IF Paths
}
# 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 | where DisplayName -match 'Dell Command'

IF($software){
Write-Output "Currently $($software.Displayname) version $($software.Version) Installed. "
}

# Software is missing install
IF(-not $software){
Write-Output "Dell Command Missing. Recommend running Dell Command Install worklet. "
exit 0
}
}else{
Write-Output "Manufacturer $($system.Manufacturer) was not recognized as Dell. "
exit 0
}

# Apply Updates
Function Start-DellCommandUpdates {

# Find dcu-cli
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# 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. "
Try {
Start-Process -FilePath $dcucli -ArgumentList "/applyUpdates" -Wait
$msg = switch ($LASTEXITCODE)
{
0 {'Command execution was successful.'}
1 {'Reboot the system to complete the operation.'}
2 {'An unknown application error has occurred'}
3 {'The current system manufacturer is not Dell.'}
4 {'The CLI was not launched with administrative privilege.'}
5 {'A reboot was pending from a previous operation.'}
6 {'Another instance of the same application (UI or CLI) is already running.'}
7 {'The application does not support the current system model.'}
8 {'No update filters have been applied or configured.'}
Default {"Unknown $LASTEXITCODE code detected."}
}
Write-Output "Dell Command Reported $msg"
}catch{ Start-Process -FilePath $dcucli -ArgumentList "/applyUpdates" -Wait }
}
Start-DellCommandUpdates

# Find dcu-cli
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# scan for update
$xml = 'C:\ProgramData\dell\DCIUpdatesReport\DCUApplicableUpdates.xml'
Remove-Item $xml -force # always start with new scan report
$scan = Start-Process "$dcucli" -ArgumentList "/scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport" -Wait
IF((Get-ChildItem $xml).LastWriteTime -gt (Get-Date).AddMinutes(-5)){
exml]$updates = Get-Content "$xml"
}else{
$msg = switch ($LASTEXITCODE)
{
0 {'Command execution was successful.'}
1 {'Reboot the system to complete the operation.'}
2 {'An unknown application error has occurred'}
3 {'The current system manufacturer is not Dell.'}
4 {'The CLI was not launched with administrative privilege.'}
5 {'A reboot was pending from a previous operation.'}
6 {'Another instance of the same application (UI or CLI) is already running.'}
7 {'The application does not support the current system model.'}
8 {'No update filters have been applied or configured.'}
Default {"Unknown $LASTEXITCODE code detected."}
}
Write-Output "Dell Command Reported $msg"
IF($LASTEXITCODE -eq 5){Write-Output "Reboot before running again. "; exit 0}
IF((Test-Path $xml) -eq $false){Write-Output "Failed to Scan."}
}

# Get Activity
Function Get-DellCommandActivity {
# Get Activity Log and parse intalled updates in last 24 hours
nxml]$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 {tdatetime]$_.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.','')
ipscustomobject] @{
timestamp = $timestamp
message = $message
}
}
foreach ($event in $events)
{
Write-Output "$($event.timestamp) $($event.message). "
}
}
#Write-Output "Attempting to Install Dell Command Updates."
$activity = Get-DellCommandActivity

# Write Activity to Log
foreach ($event in $activity){
Write-Output "$event"
}

# If no activity existed
IF($activity.count -eq 0){
# Find dcu-cli
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# if Dell Command is running stop the process
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

# Get Activity
$activity = Get-DellCommandActivity
foreach ($event in $activity){
Write-Output "$event"
}

# If activity still does not exist
IF($activity.count -eq 0){
IF(Test-Path $dcucli){
Write-Output "Something isn't working right. Recommend running this locally and analyzing output: '$dcucli' /applyUpdates "
Write-Output $activity
}else{Write-Output "Unable to locate Dell Command. "}
}
}

 


Thanks Jack. Will give it a try.


Hi Jack.

I ran your Worklet on a Dell laptop that I know has 5 updates available updates (manually ran Dell Command Update but did not install updates) and here’s what the activity log shows...

It appears to be checking for updates but not installing them. Also, the activity log on the laptop does not show any updates installed.

Any suggestions?


Please disregard my previous message. Your worklet is working like a champ. I just needed to be more patient. Thanks again.


I’ve been using this worklet and for the most part its working well.  Ive had to modify it because of problems in our environment but am currently tracking down two problems which might be related.

Ive set the policy to reboot when the remediation script is run with deferal (important to us) and the evaluation script is sometimes not detecting no updates and therefore some users are getting reboots every day as far as I can tell.  Actually, it may be that the users arent being updated and eval script is working as designed.  

The other is Im getting the following error on a small # of devices which might explain things but not sure.

 

Dell Command Reported Command execution was successful.
Something isn't working right. Recommend running this locally and analyzing output: 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe' /applyUpdates

Standard Error: 
Cannot convert value "System.Objecte]" to type "System.Xml.XmlDocument". Error: "'.', hexadecimal value 0x00, is an 
invalid character. Line 1430, position 14."
At C:\Program Files (x86)\Automox\execDir3754439104\execcmd2592661149.ps1:198 char:9
+         +xml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\ ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) ], RuntimeException
    + FullyQualifiedErrorId : InvalidCastToXmlDocument
 
Cannot convert value "System.Objectc]" to type "System.Xml.XmlDocument". Error: "'.', hexadecimal value 0x00, is an 
invalid character. Line 1430, position 14."
At C:\Program Files (x86)\Automox\execDir3754439104\execcmd2592661149.ps1:198 char:9
+         sxml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\ ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) r], RuntimeException
    + FullyQualifiedErrorId : InvalidCastToXmlDocument


In addition Im getting a ton of “Something isnt working right” with no standard error.

So I cant move this to production until I narrow these down and its not easy to take control of a users device to troubleshoot. I need a method to trap these errors in the remediation log.

One change I made for I think Win 11 devices to determin which dcu_cli to run.  
  # find dcu-cli.exe
  $x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
  $x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'

  if (Test-Path $x86) {$dcucli = $x86}
      elseif (Test-Path $x64) {$dcucli = $x64}
      else {
            write-output "DCU_CLI.EXE not found, aborting."
            exit 0
           }

To Automox:  Ask the creator of this script for permission to use, put guardrails on it and this would be a MAJOR enhancement to your tool.


@Barchetta 

Logging during eval code may help unlock what’s going on during that portion of execution

  • There is a $log variable that will update logs when dell command finds updates to install meeting a threshold of 0 days if user is admin and 7 days if not. 
    $log = 'C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt'
  • With the addition of detecting when DCU_CLI.exe is not found, you could even write that event​​​​​​​. "$(Get-Timestamp)`t DCU_CLI.exe not found" | out-file -FilePath $log -Append
  • Going a step further, one could also add logic to write to the log file should the XML file containing dell command line activity not be readable for whatever reason, it lets you know

When you see this error

At C:\Program Files (x86)\Automox\execDir3754439104\execcmd2592661149.ps1:198 char:9
+         axml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\ …

 

It is a result of failing to read the XML file for what seems to be represented as an invalid character for an XML document. Might be able to track down what character that is, parse it out before telling PowerShell to read it as an XML doc. 

Function Get-DellCommandActivity {
# Get Activity Log and parse intalled updates in last 24 hours
$al = "C:\ProgramData\dell\UpdateService\Log\Activity.log"
IF(Test-Path $al){
try{ axml]$a = Get-Content $al } catch {}
$range = (Get-Date).AddHours(-8)
# 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.','')
fpscustomobject] @{
timestamp = $timestamp
message = $message
}
}
IF($events){
foreach ($event in $events){
Write-Output "$($event.timestamp) $($event.message). "
}
}else{
IF($a){
Write-Output "No events matching 'found' updates or 'Checking for updates'..."
}else{
Write-Output "Unable to import C:\ProgramData\dell\UpdateService\Log\Activity.log for review."
}
}
}else{
Write-Output "Unable to find C:\ProgramData\dell\UpdateService\Log\Activity.log"
}
}

 


@Barchetta

Logging during eval code may help unlock what’s going on during that portion of execution

  • There is a $log variable that will update logs when dell command finds updates to install meeting a threshold of 0 days if user is admin and 7 days if not. 
    $log = 'C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt'
  • With the addition of detecting when DCU_CLI.exe is not found, you could even write that event. "$(Get-Timestamp)`t DCU_CLI.exe not found" | out-file -FilePath $log -Append
  • Going a step further, one could also add logic to write to the log file should the XML file containing dell command line activity not be readable for whatever reason, it lets you know

When you see this error

At C:\Program Files (x86)\Automox\execDir3754439104\execcmd2592661149.ps1:198 char:9
+         xml]$a = Get-Content "C:\ProgramData\dell\UpdateService\Log\ …

 

It is a result of failing to read the XML file for what seems to be represented as an invalid character for an XML document. Might be able to track down what character that is, parse it out before telling PowerShell to read it as an XML doc. 

Function Get-DellCommandActivity {
# Get Activity Log and parse intalled updates in last 24 hours
$al = "C:\ProgramData\dell\UpdateService\Log\Activity.log"
IF(Test-Path $al){
try{ xml]$a = Get-Content $al } catch {}
$range = (Get-Date).AddHours(-8)
# Write output on Checking Updates
$events = $a.LogEntries.LogEntry | Select timestamp,message | where {adatetime]$_.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
}
}
IF($events){
foreach ($event in $events){
Write-Output "$($event.timestamp) $($event.message). "
}
}else{
IF($a){
Write-Output "No events matching 'found' updates or 'Checking for updates'..."
}else{
Write-Output "Unable to import C:\ProgramData\dell\UpdateService\Log\Activity.log for review."
}
}
}else{
Write-Output "Unable to find C:\ProgramData\dell\UpdateService\Log\Activity.log"
}
}

 

Thank you so much for this response. Not sure if you have updated this script but if so please send :)

What I did is took the eval and put it into the remediation so I can see what is happening..  I have no easy to retrieve that log.. Would be wonderful if Automox added that function.

Anyway.. I need that log for sure… and going to try and get it one way or another. thanks.


Sorry, I wasnt very clear on my last post.. what I meant to say was Im getting a ton of these which tells me the evaluation script should not have run.. but when I put the eval script into the remediation it looks to me like the eval should have exited with 0.. so Im confused as to why Im seeing so many of these which is certainly causing a reboot for no reason.

Standard Output: 
Currently Dell Command | Monitor Dell Command | Update for Windows Universal version 10.7.0.232 5.4.0 Installed. 
Starting Dell Command Update Process. 
Dell Command Reported Command execution was successful.
Starting Dell Command Scan. 
2024-09-30 09:37 PM found o0] updates. 
2024-09-30 09:40 PM Checking for updates. 
2024-10-01 01:43 AM Checking for updates. 
2024-10-01 05:46 AM Checking for updates. 
2024-10-01 09:01 AM Checking for updates. 
2024-10-01 09:02 AM Checking for updates.


Hi @Barchetta 

I’ve never run this worklet in reboot mode as no logic exists to detect if that reboot is necessary or not and Automox will reboot regardless of outcome. 

 

To get at why a device runs remediation code, I’d update the Eval code for installing updates with Dell Command and another to collect the log file in question and read it to the activity log. 

 

Use a worklet with this in the remediation section and exit 1 in the eval section:

Get-Content C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt

 

Eval code that logs to C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt

$system = Get-WmiObject win32_computersystem
IF($system.Manufacturer -match "Dell"){

# Setup Logging
$log = 'C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt'
Function Get-Timestamp{
return (get-date -f 'yyyy-MM-dd hh:mm tt')
}

Function Get-DCUCLI-Exitcode ($code){
switch ($CODE)
{
0 {'Command execution was successful.'}
1 {'Reboot the system to complete the operation.'}
2 {'An unknown application error has occurred'}
3 {'The current system manufacturer is not Dell.'}
4 {'The CLI was not launched with administrative privilege.'}
5 {'A reboot was pending from a previous operation.'}
6 {'Another instance of the same application (UI or CLI) is already running.'}
7 {'The application does not support the current system model.'}
8 {'No update filters have been applied or configured.'}
Default {"Unknown $LASTEXITCODE code detected."}
}
}

# find dcu-cli.exe
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# DCU_CLI.exe missing, exit script.
IF(!$dcucli){
$msg = "dcu-cli.exe missing. no action"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

# Log file for updates
$xml = 'C:\ProgramData\dell\DCIUpdatesReport\DCUApplicableUpdates.xml'
Remove-Item $xml -force

# use DCU_CLI.exe to scan for updates
$scan = Start-Process "$dcucli" -ArgumentList "/scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport" -Wait

IF(Test-Path $xml){

# Scan produced XML results analyze
IF((Get-ChildItem $xml).LastWriteTime -gt (Get-Date).AddMinutes(-5)){
/xml]$updates = Get-Content "$xml"
}else{
$r1 = Get-DCUCLI-Exitcode -code $LASTEXITCODE
$msg = "XML was too old. Dell Command Reported $r1"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
}

# Get users and admins
$user = (Get-WmiObject -Class Win32_ComputerSystem).UserName
$admins = (net localgroup administrators).where({$_ -match '-{79}'},'skipuntil') -notmatch '-{79}|The command completed'

# Set threshold to install Dell Driver Updates
IF($user -in $admins){
# is an admin - instant install
$threshold = 0
}else{
# is not admin - add 7 days before install
$threshold = 7
}

IF($updates.updates.update){
# Loop and log
ForEach($update in $updates.updates.update){
$age = New-TimeSpan $(-datetime]$update.date) (Get-Date)
IF($age.Days -ge $threshold){
$msg = "$($update.urgency) | $($update.category) | $($update.date) | $($update.name)"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
$i++
}
}
# Missing Updates
IF($i -gt 0){
$msg = "Found $i updates to install. Run remediation code."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 1
}

}else{
# Not Missing Updates
$msg = "Found $i updates to install. Not running remediation code."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

}else{
# XML Missing, cannot properly evaluate
$msg = "Failed to Run: dcu-cli.exe /scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append

# Collect exit code and log
$r2 = Get-DCUCLI-Exitcode -code $LASTEXITCODE
$msg = "Dell Command last exit code $r2"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

}else{
# Not Dell
$msg = "Not Dell PC. No Action."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

 


Hi @Barchetta 

I’ve never run this worklet in reboot mode as no logic exists to detect if that reboot is necessary or not and Automox will reboot regardless of outcome. 

 

To get at why a device runs remediation code, I’d update the Eval code for installing updates with Dell Command and another to collect the log file in question and read it to the activity log. 

 

Use a worklet with this in the remediation section and exit 1 in the eval section:

Get-Content C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt

 

Eval code that logs to C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt

$system = Get-WmiObject win32_computersystem
IF($system.Manufacturer -match "Dell"){

# Setup Logging
$log = 'C:\ProgramData\Temp\DellCommand-Automox-Worklet.txt'
Function Get-Timestamp{
return (get-date -f 'yyyy-MM-dd hh:mm tt')
}

Function Get-DCUCLI-Exitcode ($code){
switch ($CODE)
{
0 {'Command execution was successful.'}
1 {'Reboot the system to complete the operation.'}
2 {'An unknown application error has occurred'}
3 {'The current system manufacturer is not Dell.'}
4 {'The CLI was not launched with administrative privilege.'}
5 {'A reboot was pending from a previous operation.'}
6 {'Another instance of the same application (UI or CLI) is already running.'}
7 {'The application does not support the current system model.'}
8 {'No update filters have been applied or configured.'}
Default {"Unknown $LASTEXITCODE code detected."}
}
}

# find dcu-cli.exe
$x86 = 'C:\Program Files (x86)\Dell\CommandUpdate\dcu-cli.exe'
$x64 = 'C:\Program Files\Dell\CommandUpdate\dcu-cli.exe'
IF((Test-Path $x86) -eq $true){$dcucli = $x86}
IF((Test-Path $x64) -eq $true){$dcucli = $x64}

# DCU_CLI.exe missing, exit script.
IF(!$dcucli){
$msg = "dcu-cli.exe missing. no action"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

# Log file for updates
$xml = 'C:\ProgramData\dell\DCIUpdatesReport\DCUApplicableUpdates.xml'
Remove-Item $xml -force

# use DCU_CLI.exe to scan for updates
$scan = Start-Process "$dcucli" -ArgumentList "/scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport" -Wait

IF(Test-Path $xml){

# Scan produced XML results analyze
IF((Get-ChildItem $xml).LastWriteTime -gt (Get-Date).AddMinutes(-5)){
xml]$updates = Get-Content "$xml"
}else{
$r1 = Get-DCUCLI-Exitcode -code $LASTEXITCODE
$msg = "XML was too old. Dell Command Reported $r1"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
}

# Get users and admins
$user = (Get-WmiObject -Class Win32_ComputerSystem).UserName
$admins = (net localgroup administrators).where({$_ -match '-{79}'},'skipuntil') -notmatch '-{79}|The command completed'

# Set threshold to install Dell Driver Updates
IF($user -in $admins){
# is an admin - instant install
$threshold = 0
}else{
# is not admin - add 7 days before install
$threshold = 7
}

IF($updates.updates.update){
# Loop and log
ForEach($update in $updates.updates.update){
$age = New-TimeSpan $(wdatetime]$update.date) (Get-Date)
IF($age.Days -ge $threshold){
$msg = "$($update.urgency) | $($update.category) | $($update.date) | $($update.name)"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
$i++
}
}
# Missing Updates
IF($i -gt 0){
$msg = "Found $i updates to install. Run remediation code."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 1
}

}else{
# Not Missing Updates
$msg = "Found $i updates to install. Not running remediation code."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

}else{
# XML Missing, cannot properly evaluate
$msg = "Failed to Run: dcu-cli.exe /scan -silent -report=C:\ProgramData\dell\DCIUpdatesReport"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append

# Collect exit code and log
$r2 = Get-DCUCLI-Exitcode -code $LASTEXITCODE
$msg = "Dell Command last exit code $r2"
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

}else{
# Not Dell
$msg = "Not Dell PC. No Action."
"$(Get-Timestamp)`t$msg" | out-file -FilePath $log -Append
exit 0
}

Thanks for this again.  In regards to reboots.. What occurs with DCU when a reboot is needed and no reboot is forced by automox?  Maybe I am doing this needlessly.  My concern is the dcu is either never going to force a reboot, or worse, it is with a single prompt and no ability to defer.

 

 


Thanks for this again.  In regards to reboots.. What occurs with DCU when a reboot is needed and no reboot is forced by automox?  Maybe I am doing this needlessly.  My concern is the dcu is either never going to force a reboot, or worse, it is with a single prompt and no ability to defer.

 

 @Barchetta, the update being installed by DCU will wait to install until next reboot. You might observe Bitlocker being suspended for say a BIOS firmware update. Update operations will suspend until the reboot occurs. 

The DCU update process can also include enforced reboots. For example, adding this will tell DCU to reboot if needed:

dcu-cli.exe /applyUpdates -reboot=enable

 

My current update strategy is to install all DCU updates without a reboot daily. Also daily patching policy with a patch age restrictions across multiple policies including Browsers, OS, 3rd Party, and Defender Signatures. 

For reboots there is a separate process running daily that triggers if a device shows a pending update for windows update or has exceeded an uptime of 28 days. Either way, I’m getting a reboot monthly.

 

This Reference Guide from Dell has all the command line options:

https://dl.dell.com/content/manual17524146-dell-command-update-version-5-x-reference-guide.pdf

This Worklet is a custom powershell Toast Pop-up

Worklet - Toast Notifications with Branding and Ignores Focus Assist


Thanks for this again.  In regards to reboots.. What occurs with DCU when a reboot is needed and no reboot is forced by automox?  Maybe I am doing this needlessly.  My concern is the dcu is either never going to force a reboot, or worse, it is with a single prompt and no ability to defer.

 

 @Barchetta, the update being installed by DCU will wait to install until next reboot. You might observe Bitlocker being suspended for say a BIOS firmware update. Update operations will suspend until the reboot occurs. 

The DCU update process can also include enforced reboots. For example, adding this will tell DCU to reboot if needed:

dcu-cli.exe /applyUpdates -reboot=enable

 

My current update strategy is to install all DCU updates without a reboot daily. Also daily patching policy with a patch age restrictions across multiple policies including Browsers, OS, 3rd Party, and Defender Signatures. 

For reboots there is a separate process running daily that triggers if a device shows a pending update for windows update or has exceeded an uptime of 28 days. Either way, I’m getting a reboot monthly.

 

This Reference Guide from Dell has all the command line options:

https://dl.dell.com/content/manual17524146-dell-command-update-version-5-x-reference-guide.pdf

This Worklet is a custom powershell Toast Pop-up

Worklet - Toast Notifications with Branding and Ignores Focus Assist

Really appreciate this.  

We have been looking at that toast notification worklet for a few weeks. It looks a a bit daunting but If I could dig in for 4 hrs I could make it happen and its a very eloquent method.

 

Thanks again for taking all the time on this and thanks for sharing your most recent eval, I see some great updates.  

 



 

 


Reply