We are using mandatory profiles on our VDI deployment and needed a solution for clickonce applications. We deployed servers for hosting published applications with roaming profiles and configured the following script to accomplish running the applications and maintaining their installed state so they didn't need to be re-installed every time the user opened them.
Both applications were started differently so modifications had to be made to each.. depending on how the developer built their app you will need to make modifications to this script. During testing I just published a powershell prompt and then once we had it where it worked correctly we wrapped it into an exe with PowerShell Studio.
*The wait-forprocess function I found here - https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/waiting-for-process-launch
Brief Description:
Exists:
1. Imports the registry file.
2. Launches dfsvc.exe with short delay and saves process information to variable.
3. Launches ClickOnce.Application
If there is an update it will prompt the user to install else it will just launch existing version.
Wait-ForProcess function continuously checks for the applications process name.
4. Exports the updated registry information, if any, to _Config.reg
5. Waits for user to exit application.
6. Upon exit terminates the dfsvc process from the variable information in step 2.
Does Not Exist:
1. Created Application directory in users appdata\roaming folder.
2. Launches dfsvc.exe with short delay and saves process information to variable.
3. Launches ClickOnce.Application
If there is an update it will prompt the user to install else it will just launch existing version.
Wait-ForProcess function continuously checks for the applications process name.
4. Exports the updated registry information, if any, to _Config.reg
5. Waits for user to exit application.
6. Upon exit terminates the dfsvc process from the variable information in step 2.
Everything capitalized would need to be modified for your particular application.
Example A - This application ran from a file that was stored on the local server.
function Wait-ForProcess
{
param (
$Name,
[Switch]$IgnoreAlreadyRunningProcesses
)
if ($IgnoreAlreadyRunningProcesses){
$NumberOfProcesses = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count
}
else{
$NumberOfProcesses = 0
}
while ((Get-Process -Name $Name -ErrorAction SilentlyContinue).Count -eq $NumberOfProcesses){
Start-Sleep -Milliseconds 400
}
}
$reg_config_path = "C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg"
if (Test-Path $reg_config_path) {
reg import C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg
$dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru
Start-Sleep -Seconds 2
Start-Process .\APPLICATION_NAME.application
Wait-ForProcess -name "APPLICATION_PROCESS_NAME" -IgnoreAlreadyRunningProcesses
reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y
Wait-Process -Name APPLICATION_PROCESS_NAME
Stop-Process $dfsvc_process.id
}
else {
mkdir c:\users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER -ErrorAction SilentlyContinue
$dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru
Start-Sleep -Seconds 2
Start-Process .\APPLICATION_NAME.application
Wait-ForProcess -name "APPLICATION_PROCESS_NAME" -IgnoreAlreadyRunningProcesses
reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y
Wait-Process -Name APPLICATION_PROCESS_NAME
Stop-Process $dfsvc_process.id
}
Example B - This application would only work if initalized from IE. Vendor restricted running the application from direct access, Chrome, Firefox, etc.
function Wait-ForProcess {
param (
$Name,
[Switch]$IgnoreAlreadyRunningProcesses
)
if ($IgnoreAlreadyRunningProcesses) {
$NumberOfProcesses = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count
}
else {
$NumberOfProcesses = 0
}
while ((Get-Process -Name $Name -ErrorAction SilentlyContinue).Count -eq $NumberOfProcesses) {
Start-Sleep -Milliseconds 400
}
$reg_config_path = "C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg"
if (Test-Path $reg_config_path) {
reg import C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg
$dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru
Start-Sleep -Seconds 2
Start-Process iexplore.exe URL_TO_CLICKONCE_APPLICATION
Wait-ForProcess -Name APPLICATION_PROCESS_NAME -IgnoreAlreadyRunningProcesses
Wait-Process APPLICATION_PROCESS_NAME
reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y
Stop-Process $dfsvc_process.id
}
else {
mkdir c:\users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\
Start-Process "C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe"
Start-Sleep -Seconds 2
start-process iexplore.exe URL_TO_CLICKONCE_APPLICATION
Wait-ForProcess -name APPLICATION_PROCESS_NAME -IgnoreAlreadyRunningProcesses
reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y
Wait-Process -Name APPLICATION_PROCESS_NAME
reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y
Stop-Process $dfsvc_process.id
}
seamless Clickonce
in XenDesktop 7.x
Posted
We are using mandatory profiles on our VDI deployment and needed a solution for clickonce applications. We deployed servers for hosting published applications with roaming profiles and configured the following script to accomplish running the applications and maintaining their installed state so they didn't need to be re-installed every time the user opened them.
Both applications were started differently so modifications had to be made to each.. depending on how the developer built their app you will need to make modifications to this script. During testing I just published a powershell prompt and then once we had it where it worked correctly we wrapped it into an exe with PowerShell Studio.
*The wait-forprocess function I found here - https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/waiting-for-process-launch
Brief Description:
Exists:
1. Imports the registry file.
2. Launches dfsvc.exe with short delay and saves process information to variable.
3. Launches ClickOnce.Application
If there is an update it will prompt the user to install else it will just launch existing version.
Wait-ForProcess function continuously checks for the applications process name.
4. Exports the updated registry information, if any, to _Config.reg
5. Waits for user to exit application.
6. Upon exit terminates the dfsvc process from the variable information in step 2.
Does Not Exist:
1. Created Application directory in users appdata\roaming folder.
2. Launches dfsvc.exe with short delay and saves process information to variable.
3. Launches ClickOnce.Application
If there is an update it will prompt the user to install else it will just launch existing version.
Wait-ForProcess function continuously checks for the applications process name.
4. Exports the updated registry information, if any, to _Config.reg
5. Waits for user to exit application.
6. Upon exit terminates the dfsvc process from the variable information in step 2.
Everything capitalized would need to be modified for your particular application.
Example A - This application ran from a file that was stored on the local server. function Wait-ForProcess { param ( $Name, [Switch]$IgnoreAlreadyRunningProcesses ) if ($IgnoreAlreadyRunningProcesses){ $NumberOfProcesses = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count } else{ $NumberOfProcesses = 0 } while ((Get-Process -Name $Name -ErrorAction SilentlyContinue).Count -eq $NumberOfProcesses){ Start-Sleep -Milliseconds 400 } } $reg_config_path = "C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg" if (Test-Path $reg_config_path) { reg import C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg $dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru Start-Sleep -Seconds 2 Start-Process .\APPLICATION_NAME.application Wait-ForProcess -name "APPLICATION_PROCESS_NAME" -IgnoreAlreadyRunningProcesses reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y Wait-Process -Name APPLICATION_PROCESS_NAME Stop-Process $dfsvc_process.id } else { mkdir c:\users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER -ErrorAction SilentlyContinue $dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru Start-Sleep -Seconds 2 Start-Process .\APPLICATION_NAME.application Wait-ForProcess -name "APPLICATION_PROCESS_NAME" -IgnoreAlreadyRunningProcesses reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y Wait-Process -Name APPLICATION_PROCESS_NAME Stop-Process $dfsvc_process.id } Example B - This application would only work if initalized from IE. Vendor restricted running the application from direct access, Chrome, Firefox, etc. function Wait-ForProcess { param ( $Name, [Switch]$IgnoreAlreadyRunningProcesses ) if ($IgnoreAlreadyRunningProcesses) { $NumberOfProcesses = (Get-Process -Name $Name -ErrorAction SilentlyContinue).Count } else { $NumberOfProcesses = 0 } while ((Get-Process -Name $Name -ErrorAction SilentlyContinue).Count -eq $NumberOfProcesses) { Start-Sleep -Milliseconds 400 } $reg_config_path = "C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg" if (Test-Path $reg_config_path) { reg import C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg $dfsvc_process = start-process C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe -PassThru Start-Sleep -Seconds 2 Start-Process iexplore.exe URL_TO_CLICKONCE_APPLICATION Wait-ForProcess -Name APPLICATION_PROCESS_NAME -IgnoreAlreadyRunningProcesses Wait-Process APPLICATION_PROCESS_NAME reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y Stop-Process $dfsvc_process.id } else { mkdir c:\users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\ Start-Process "C:\Windows\Microsoft.NET\Framework\v4.0.30319\dfsvc.exe" Start-Sleep -Seconds 2 start-process iexplore.exe URL_TO_CLICKONCE_APPLICATION Wait-ForProcess -name APPLICATION_PROCESS_NAME -IgnoreAlreadyRunningProcesses reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y Wait-Process -Name APPLICATION_PROCESS_NAME reg export HKCU\SOFTWARE\Classes\Software C:\Users\$env:username\appdata\roaming\APPLICATION_ROAMING_FOLDER\APPLICATION_config.reg /y Stop-Process $dfsvc_process.id }