Today, I was called in to devise a solution to allow some DDS-CAD users (NO LOCAL ADMINS!) to install the necessary DDS-CAD updates themselves. Of course, this idea could also be used for other company apps!
Of course, we could buy the Intune Suite add-on and start using Endpoint Privilege Management, but it was just one app this time!
Please Note: This idea can also be used to ensure that normal/standard users have the privilege to install some software themselves.
1. The Non Local Admin Issue
Without a problem, there could be no solution. So, let me first explain the issue a little bit more. Many of our customers use specific software for their field of work. As a good example, we also deliver Microsoft 365 IT services to “technical installation companies,” and some of them are using DDS-CAD
Please note: Security is paramount, so no local admin privileges for anyone!
When enrolling their device, they could install DDS-CAD independently by opening the Company Portal app and just clicking “install”.
The customer was very happy that we could allow non-local admin users to install or update applications on their own. If the customer is happy, we are happy.
Like every app, DDS-CAD needs to be kept up to date. Luckily (at least what we thought at first) there is a built-in tool to check for updates. By pressing the update button, it launches the DdsWebupdate.exe from the C:\Program Files\Data Design System\MEP 17\Exe folder.
As this folder exists in the program files folder, it is also allowed in the default Applocker policy. So we can be 100% sure Applocker isn’t going to block it. To see what was going to happen, we opened this EXE file. When we opened the EXE file it started looking for updates but after waiting a few minutes, nothing changed. It was still stuck on the “looking for updates” prompt.
That’s odd! So we killed the process and tried to do the same, but this time, we launched the process as admin, and immediately, we were prompted to start updating the installation files!
Damn…I was hoping it gave us an error… so we need to be an admin to update this App on our own. That isn’t great at all! So what now? Of course, you could make sure you could use additional third-party patching solutions like the great Scappman tool. But unfortunately, DDS-CAD is not yet on their application list. So we were like, why not give the user some privileges to do this themselves?
Some apps need to be updated weekly or even daily, and as I told you above, sometimes the app itself isn’t on the application list supported by third-party patching solutions.
2. The Solution
We need a solution, that’s for sure. Let me explain what we did before I showed you the PowerShell script.
I had the brilliant idea (looking back at the script, I love it… )
We want to create a new scheduled task and let the task scheduler start updating the app when we want it! So we created a PowerShell script to ensure a new scheduled task is created. This nice scheduled task would launch a PowerShell-encoded command to launch that DdsWebupdate.exe process.
As expected, the “search for updates” screen would also be shown in the system context and NOT in the user’s context. Luckily we already had the nice OOB Windows update script, which also shows a toast message from the system context to the logged-in user’s context with the use of Serviceui.exe
https://call4cloud.nl/2022/01/deploy-oob-update-powershell/
So, we re-used my previously created script to use serviceui.exe to show the update prompt to the user instead of the system. So far so good, we finished the first part of this journey.
Now we have created the scheduled task to run that process as system but to show the Windows/Prompt in the users context, we still had some more work to do. We still needed to change the permissions to run the scheduled task and create a shortcut on the public desktop. With this task scheduler shortcut, any user could use schtasks.exe to run that specific task!
3. permitting users to run a system scheduled task
But how the hell would we give a user the possibility to run that scheduled task on his own? Because a regular user doesn’t have permission to run tasks configured as system/administrator manually.
Way back, when you wanted to ensure your regular end user could run a system task, you could just change the ACL on the XML file in c:\windows\system32\tasks\. But with Windows 10, this doesn’t work anymore.
After some research, we found a nice website with all the information we need on it.
Windows: Run task scheduler task as limited user (michlstechblog.info)
Reading that blog made me realize we needed to change some registry values and some Security Descriptors (SD)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree
But that wasn’t sufficient, we also needed to change the SecurityDescriptor of the specific Task in the TaskCache\Tasks\ID registry key.
Luckily the ID we need to get the right task, was already available in the first registry key we changed. Now we have everything we need, we still need to change the Access Mask to 1179817
Long story short, the script changes the permissions so any user could run that task. Isn’t that beautiful? And with a shortcut on the user’s desktop, it is very easy to launch that update process!
Please Note: I also added the second version of changing scheduled task permissions, but still need to test it some more
4. The Results
But before I show you the script, we must look at the results. First, we need to see the shortcut to the scheduled task and, of course, the scheduled task itself.
Now, let’s press the button to launch the update process
Yes, Yes… as shown above, it started updating. After some minutes of waiting, DDS-CAD was successfully updated
5. The PowerShell Script
To finish the blog… the PowerShell script itself! Hopefully, you can read and understand it with the explanation I gave you earlier. If not please send me a DM 🙂
#################################
#Configure encoded commands here#
#################################
$encodedcommand1 = "JgAgACIAQwA6AFwAUAByAG8AZwByAGEAbQAgAEYAaQBsAGUAcwBcAEQAYQB0AGEAIABEAGUAcwBpAGcAbgAgAFMAeQBzAHQAZQBtAFwATQBFAFAAIAAxADcAXABFAHgAZQBcAEQAZABzAFcAZQBiAFUAcABkAGEAdABlAC4AZQB4AGUAIgA="
#########################################################################################
#Toast Example: please convert it to base64 and adjust the $encodedcommand above #
#read more on https://call4cloud.nl/2021/12/code-name-the-log-cleaner/ #
# #
# Encoded Command | Notifying and Installing The Update #
###########################################################################################
#& "C:\Program Files\Data Design System\MEP 17\Exe\DdsWebUpdate.exe"
##############################################################################################
#Download and install ServiceUT#
$path = "C:\program files (x86)\service"
New-Item -ItemType Directory -Force -Path $path
Invoke-WebRequest "https://call4cloud.nl/wp-content/uploads/2021/07/ServiceUI.zip" -OutFile "$path\ZippedFile.zip"
Expand-Archive -LiteralPath "$path\ZippedFile.zip" -DestinationPath "$path" -force
####################################################
####Install the Update task ! #
###################################################
$triggers = New-ScheduledTaskTrigger -Once -At (get-date).AddSeconds(-200); $triggers.EndBoundary = (get-date).AddSeconds(-100).ToString('s')
$Action = New-ScheduledTaskAction -Execute "c:\program files (x86)\service\ServiceUI.exe" -argument "-process:explorer.exe c:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -encodedcommand $encodedcommand1"
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable
$Null = Register-ScheduledTask -TaskName "UpdateDDSCAD" -Trigger $triggers -User "SYSTEM" -Action $Action -Settings $Settings -Force
############################################################################
####Change Permissions for the task version 2 (need to test it first ! #
###########################################################################
$scheduler = New-Object -ComObject "Schedule.Service"
$scheduler.Connect()
$task = $scheduler.GetFolder("\").GetTask("UpdateDDSCAD")
$sec = $task.GetSecurityDescriptor(0xF)
$sec = $sec + ‘(A;;GRGX;;;AU)’
###################################
#PLEASE NOTE GRGX --> 1179817 #
###################################
$task.SetSecurityDescriptor($sec, 0)
####################################################
##### Create Shortcut to task on Desktop ! #
###################################################
if (-not (Test-Path "C:\Users\Public\Desktop\Update DDS-CAD.lnk"))
{
$null = $WshShell = New-Object -comObject WScript.Shell
$path = "C:\Users\Public\Desktop\Update DDS-CAD.lnk"
$targetpath = "C:\Windows\System32\schtasks.exe"
$Shortcut = $WshShell.CreateShortcut($path)
$Shortcut.TargetPath = $targetpath
$Shortcut.Arguments = '/run /TN "UpdateDDSCAD"'
$Shortcut.Save()
}
Conclusion
I have been saying this a lot: Giving your end-users the “feeling” they could do whatever they want when they want is just fantastic.
Hopefully, this solution could help if you received the same question as we did!