How I Fell in Love with App Updates

Today I was called in to come up with a solution to give some DDS-CAD users (NO LOCAL ADMINS!) the possibility to install the necessary DDS-CAD updates themselves. Of course, this idea could be used for other company apps!

I will divide this blog into multiple parts

  1. The Issue
  2. The Solution
  3. Changing Scheduled task permissions
  4. The results
  5. The Script

Without a problem, there could be no solution. So let me first explain the issue a little bit more. A lot of our customers are using some specific software for their field of work they are in. 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: As always Security is of utmost importance, so no-local admin privileges for no one!

When enrolling their device, they could install DDS-CAD on their own by opening the Company Portal app and just clicking “install”.

The customer was very happy we could give non-local admin users the possibility to install software on their own. And If the customer is happy we are happy.

But 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 FilesData Design SystemMEP 17Exe 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 it started updating the installation files!

Afbeelding met tekst  Automatisch gegenereerde beschrijving

Damn…I hoped 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?

Because some apps need to be updated each week or even each day and like I told you above, sometimes the app itself isn’t on the application list that is supported by third-party patching solutions.

So we need a solution, that’s for sure. So let me explain what we did before I am going to show you the whole PowerShell script.

I had the brilliant idea (looking back at the script, I just love it… )

shameless self promotion gifs | WiffleGif

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 make sure a new scheduled task will be 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

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!

But how the hell were we going to give a user the possibility to run that scheduled task on his own. Because a regular user doesn’t have the permission to manually run tasks, that were configured as system/administrator.

Way way back, when you want to make sure your regular end user could run a system task, you could just change the ACL on the XML file in c:windowssystem32tasks. 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)

HKLMSOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTree

But that wasn’t sufficient, we also needed to change the SecurityDescriptor of the specific Task in the TaskCacheTasksID 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

Afbeelding met tekst  Automatisch gegenereerde beschrijving

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

But before I am showing you the script, we still need to take a look at the results. First the shortcut to the scheduled task and of course the scheduled task itself

Now let’s press the button to launch the update process

Afbeelding met tekst  Automatisch gegenereerde beschrijving

Yes Yes… as shown above it started updating. After some minute waiting, DDS-CAD was successfully updated

Afbeelding met tekst  Automatisch gegenereerde beschrijving

To finish the blog… the PowerShell script itself! Hopefully, you could 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/05/the-laps-reloaded/ #
# #
# Encoded Command | Notifying and Installing The Update #
###########################################################################################

#& "C:Program FilesData Design SystemMEP 17ExeDdsWebUpdate.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 "$pathZippedFile.zip"
Expand-Archive -LiteralPath "$pathZippedFile.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)serviceServiceUI.exe" -argument "-process:explorer.exe c:WindowsSystem32WindowsPowershellv1.0powershell.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  ! #
###################################################

$sTaskPath="UpdateDDSCAD"
$UserToAdd="gebruikers"
$SID=(get-localgroup $UserToAdd).SID.Value
$AccessMask=1179817
		######################################################################################
		# 1179817-> 0x1200a9 (SYSTEM, Authenticated User, Local Service, Network Service)    #
		######################################################################################
$oNewACE=new-object System.Security.AccessControl.CommonAce([System.Security.AccessControl.AceFlags]::None,`
[System.Security.AccessControl.AceQualifier]::AccessAllowed,`
$AccessMask,`
(new-object System.Security.Principal.SecurityIdentifier($SID)),`
$false,`
([byte[]]@()))
$oMyTaskACL=[System.Security.AccessControl.RawSecurityDescriptor]::new((Get-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTree$sTaskPath").SD,0)
$sMyTaskUID=(Get-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTree$sTaskPath").Id
$oMyTaskACL.DiscretionaryAcl.InsertACE($oMyTaskACL.DiscretionaryAcl.Count,$oNewACE)
$aACLBytes=([wmiclass]"Win32_SecurityDescriptorHelper").SDDLToBinarySD($oMyTaskACL.GetSddlForm(15)).BinarySD
New-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTree$sTaskPath" -Name "SD" -Value $aACLBytes -Type Binary -Force
New-ItemProperty "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionScheduleTaskCacheTasks$sMyTaskUID" -Name "SecurityDescriptor" -Value $oMyTaskACL.GetSddlForm(15) -Type String -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:UsersPublicDesktopUpdate DDS-CAD.lnk"))
{
$null = $WshShell = New-Object -comObject WScript.Shell
$path = "C:UsersPublicDesktopUpdate DDS-CAD.lnk"
$targetpath = "C:WindowsSystem32schtasks.exe"

$Shortcut = $WshShell.CreateShortcut($path)
$Shortcut.TargetPath = $targetpath
$Shortcut.Arguments = '/run /TN "UpdateDDSCAD"'
$Shortcut.Save()
}

I have been telling this a lot, giving your end-users the “feeling” they could do whatever they want when they want is just fantastic.

Freedom GIFs - Get the best GIF on GIPHY

Hopefully, this solution could help you if you received the same question as we did!

avatar
Rudy Oomshttps://call4cloud.nl/
Rudy is a Modern workplace architect and currently working for a company in the Netherlands, called Deltacom Steenbergen. He has been working in IT since he was 16 years old. Within these years, he gained a lot of experience in different kinds of expertise. I guess like most of you, he started working with active directory environments. In June 2021 he received the MVP status in the category Enterprise Mobility for the first time. The multi-tenant PowerShell scripted Deltacom-Cloud environment is one of his creations.

Related Articles

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Stay Connected

6,065FollowersFollow
5,933FollowersFollow

Subscribe to our newsletter

To be updated with all the latest news, offers and special announcements.

Latest Articles