Skip to main content

The case of the empty Start Menu (Windows 10)

Author
John Billekens
Technical Consultant | End User Computing

During a project I’m currently working on, with Windows 10, Citrix Xendesktop 7.9, XenServer 7.0 and RES ONE Workspace 2015 SR2 I stumbled upon a issue with RES ONE Workspace and the pinning of items in the Start Menu. I noticed that sometimes my Start Menu was empty, while I had items pinned when I logged off!? After some investigation with an engineer from RES Software, we managed to reproduce the issue in a closed test environment. At this point RES can try to fix the issue and at the time of writing no known solution is available. We still need to verify but as far as we know the issue is also still in the new version RES ONE Workspace 2016. We still needed a filled Start Menu for the time being, because currently there is no known date for the possible fix… So I created a PoSh script that will fill the Start Menu. (for the 2nd time, after the RES composer is finished) Yes I know not very pretty solution but it gets the job done and it’s a temporary fix. So here is the script I’ve made. (Building block is also available at the end for download)

<#
.SYNOPSIS  
    Restore pinned items in Winows 10 Start Menu.
.DESCRIPTION
    This script was build to (temporarily) fix a issue with RES Workspace and pinning items in the Start menu of Windows 10.
    In some occasions (Non-Persistent environments) it could happen that the Start Menu was empty after login while the xml file contained items.
    Currently this issue is being examined by RES and while they try to fix this issue this script can fill the Start Menu for you, so the users have a filled Start Menu.
.NOTES
    File Name  : PinStartItems.ps1
    Author     : John Billekens - blog.j81.nl
    Requires   : Windows 10
.LINK
    http://blog.j81.nl
.EXAMPLE
    .\PinStartItems.ps1
.EXAMPLE
    powershell.exe -ExecutionPolicy Bypass .\PinStartItems.ps1
#>

[CmdletBinding()]
param ()

function Query-ShellExperienceHost {
    [cmdletbinding()]
    param (
        [string]$Username
    )
    # Get ShellExperienceHost process info for the user specified
    $process = Get-Process -IncludeUserName -ErrorAction SilentlyContinue | Where-Object { ($_.Username -eq $UserName) -AND ($_.ProcessName -like "ShellExperienceHost")}
    if (-not ([string]::IsNullOrEmpty($Process.Id))) {
        # Get thread info and get active threads
        $query = "SELECT ThreadState,ThreadWaitReason,ProcessHandle FROM Win32_Thread WHERE ProcessHandle = $($process.Id)"
        $oThread = Get-CimInstance -Query $query
        $out = New-Object psobject -Property @{
            SessionID = $process.SessionId
            ProcessID = $process.Id
            ActiveThreads = ($oThread | Where-Object { (-not ($_.ThreadState -eq 5)) -OR (-not ($_.ThreadWaitReason -eq 5)) }).Count
        }
    }
    return $out
}

# Create eventlog item "PinStartItems"
New-EventLog -LogName Application -Source PinStartItems -ErrorAction SilentlyContinue

# Get current user
$sUserName = & $env:Systemroot\System32\whoami.exe

try {
    # Get ShellExperienceHost process data
$iBreak=0
    while ($iBreak -ne 10){
        # Sometimes it can happen the proces isn't available yet, it will wait until ready (max 30sec)
        $oOutput = Query-ShellExperienceHost -UserName $sUserName
        if (-not ([string]::IsNullOrEmpty($oOutput.SessionId))) {
            Start-Sleep -m 500
            Break
        } else {
            $iBreak++
            Start-Sleep -s 3
        }
    }
    if ($iBreak -ge 10) {
        Throw "ShellExperienceHost wasn't running on time"
    } 
    # Specify the exported file (when not using RES Workspace, copy the exported start layout file in xml format locally first)
    $tilefile="$($env:LOCALAPPDATA)\RES\WM\$($oOutput.SessionId)\WMTileFile.xml"
    if (test-path $tilefile) {
            # Set policy to import the start layout
            $sRegPath = "HKCU:\SOFTWARE\Policies\Microsoft\Windows\Explorer"
            if (-not (Test-Path -Path $sRegPath)) {
                New-Item -Path $sRegPath -Force | Out-Null
            }
            New-ItemProperty -Path $sRegPath -Name LockedStartLayout -Value 1 -PropertyType DWORD -Force | out-null
            New-ItemProperty -Path $sRegPath -Name StartLayoutFile -Value $tilefile -PropertyType String -Force | out-null
            # Kill the process so the layout can be applied
            Stop-Process -Id $oOutput.ProcessID
            $iBreak=0
            while ($iBreak -ne 10){
                # Sometimes it can happen the proces isn't available yet, it will wait until ready (max 30sec)
                $oOutput = Query-ShellExperienceHost -UserName $sUserName
                if (($oOutput.ActiveThreads -eq 0) -and (-not ([string]::IsNullOrEmpty($oOutput.ProcessID)))) {
                    Start-Sleep -m 500
                    Break
                } else {
                    $iBreak++
                    Start-Sleep -s 3
                }
            }
            if ($iBreak -ge 10) {
                Throw "ShellExperienceHost wasn't ready in time"
            } else {
                # Remove the policy items to make it possible to pin new items
                Remove-ItemProperty -Path $sRegPath -Name LockedStartLayout -Force | out-null
                Remove-ItemProperty -Path $sRegPath -Name StartLayoutFile -Force | out-null
                Stop-Process -Id $oOutput.ProcessID
            }
            Write-EventLog -LogName "Application" -Source "PinStartItems" -EventID 1 -EntryType Information -Message "`"$sUserName`" ($($oOutput.SessionId)): Restoring pinned items to the Start Menu was successfull" -Category 0
    } else {
        # The xml file was not found at the given location
        Write-EventLog -LogName "Application" -Source "PinStartItems" -EventID 2 -EntryType Warning -Message "`"$sUserName`" ($($oOutput.SessionId)): File `"$tilefile`" was not found." -Category 0
    }
} catch {
    # An error was occured, log to eventlog
    $errmessage = "`"$sUserName`" ($($oOutput.SessionId)): Restoring pinned items (`"$tilefile`") to the Start Menu was failed.`r`n`r`nError:`r`n$(($_.Exception.Message) -join [Environment]::NewLine)"
    Write-EventLog -LogName "Application" -Source "PinStartItems" -EventID 5 -EntryType Error -Message $errmessage -Category 0
}

I added this script to the Custom Resources in RES ONE Workspace (Administration / Custom Resources) in the directory Scripts. 20160806_StartMenuPinnedItems_01 Create a new shortcut under Composition / Applications. It doesn’t matter where as we don’t create a visible shortcut in the users Start Menu. 20160806_StartMenuPinnedItems_02 Add the command-line parameters for PowerShell.

%systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass %rescustomresources%\Scripts\PinStartItems.ps1

20160806_StartMenuPinnedItems_03 Disable the creation of any shortcut in the users environment. 20160806_StartMenuPinnedItems_04 Make sure that the application is run automatically and minimized. 20160806_StartMenuPinnedItems_05 Run it for all users or change accordingly. 20160806_StartMenuPinnedItems_06 Authorize the file when needed. 20160806_StartMenuPinnedItems_07 And don’t forget to add dynamic privileges. 20160806_StartMenuPinnedItems_08 At every login an entry will be made in the Application Event log so you can see if it ran ok (or if an error had occurred). 20160806_StartMenuPinnedItems_09 So that’s it. Hope I can make somebody happy with this post. Download RES ONE Workspace BuildingBlock EDIT: 18-08-2016 Script updated, added some extra checks.

Related

OptimizeEndpoint

·1 min
I’ve been using my “Windows optimize script” for a while now. Most issues are resolved and it’s been tested thoroughly. So I thought why not give it back to the community, so here it is: OptimizeEndpoint. It can be used to optimize Windows 7, 8, 8.1 and 10. (It can also be used for Windows Server versions, but this is not tested) I used the script made by Ingmar Verheij, and made some changes. It contains most of the Citrix XenDesktop Best Practices. Please don’t run the script without reviewing the options, it can damage you master image if you’re not careful! At the top of the image there are some parameters that can be set. Read the comments. Run it on your own risk. If you have issues or questions let me know.

Generate an Let's Encrypt certificate what can be used on the NetScaler

··1 min
Edit 07-04-2017: Check out my new and updated version! I’m trying to create an (PowerShell) script to automate the Let’s Encrypt certificate creation. Specifically for the Citrix NetScaler. Currently still Work In Progress… It’s not yet finished. The prerequisite is that you have a configured NetScaler (http) Content Switch vServer. The script will present you with the required configuration rules (it will also be copied to your clipboard so you only have to copy it in the cli of the NetScaler) For the meantime you can find it on GitHub: GenCertForNS on GitHub More soon (I hope)…

CtxVdStatus Script

·1 min
Today I decided to put my CtxVdStatus script on GitHub. With this script you can get an overview of your Citrix XenDesktop environment. It helped me to troubleshoot some issues. You can download/view it here