henrydenhengst

Troubleshooting Slow Logons XenApp

Aug 24th, 2015
590
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2.     .SYNOPSIS
  3.         This script outputs a breakdown of the logon process.
  4.        
  5.     .DESCRIPTION
  6.         This script gives an insight to the logon process phases.
  7.         Each phase described have a column for duration in seconds, start and end time
  8.         of the phase, and interim delay which is the time that passed between the
  9.         end of one phase and the start of the one that comes after.
  10.     http://blogs.citrix.com/2015/08/05/troubleshooting-slow-logons-via-powershell/
  11.        
  12.     .PARAMETER  <UserName <string[]>
  13.         Specifies the user name on which the script runs. The default is the user who runs the script.
  14.        
  15.     .PARAMETER  <UserDomain <string[]>
  16.         Specifies the domain name of the user on which the script runs. The default is the domain name of the user who runs the script.
  17.        
  18.     .PARAMETER  <CUDesktopLoadTime>
  19.         Specifies the duration of the Shell phase, can be used with ControlUp as passed argument.
  20.        
  21.     .LINK
  22.         For more information refer to:
  23.             http://www.controlup.com
  24.  
  25.     .EXAMPLE
  26.         C:\PS> Get-LogonDurationAnalysis -UserName Rick
  27.        
  28.         Gets analysis of the logon process for the user 'Rick' in the current domain.
  29. #>
  30.  
  31. function Get-LogonDurationAnalysis {
  32.  
  33. param (
  34.     [Parameter(Mandatory=$false)]
  35.     [Alias('User')]
  36.     [String]
  37.     $Username = $env:USERNAME,
  38.     [Parameter(Mandatory=$false)]
  39.     [Alias('Domain')]
  40.     [String]
  41.     $UserDomain = $env:USERDOMAIN,
  42.     [int]
  43.     $CUDesktopLoadTime
  44.     )
  45.     begin {
  46.     function Get-PhaseEvent {
  47.    
  48.     param (
  49.         [ValidateNotNullOrEmpty()]
  50.         [String]
  51.         $PhaseName,
  52.         [ValidateNotNullOrEmpty()]
  53.         [String]
  54.         $StartProvider,
  55.         [ValidateNotNullOrEmpty()]
  56.         [String]
  57.         $EndProvider,
  58.         [ValidateNotNullOrEmpty()]
  59.         [String]
  60.         $StartXPath,
  61.         [ValidateNotNullOrEmpty()]
  62.         [String]
  63.         $EndXPath,
  64.         [int]
  65.         $CUAddition
  66.         )
  67.  
  68.         try {
  69.             $StartEvent = Get-WinEvent -MaxEvents 1 -ProviderName $StartProvider -FilterXPath $StartXPath -ErrorAction Stop
  70.             if ($StartProvider -eq 'Microsoft-Windows-Security-Auditing' -and $EndProvider -eq 'Microsoft-Windows-Security-Auditing') {
  71.                 $EndEvent = Get-WinEvent -MaxEvents 1 -ProviderName $EndProvider -FilterXPath ("{0}{1}" -f $EndXPath,@"
  72. and *[EventData[Data[@Name='ProcessId']
  73. and (Data=`'$($StartEvent.Properties[4].Value)`')]]
  74. "@) # Responsible to match the process termination event to the exact process
  75.             }
  76.             elseif ($CUAddition) {
  77.                 Set-Variable -Name EndEvent -Value ($StartEvent | Select-Object -ExpandProperty TimeCreated).AddSeconds($CUAddition)
  78.             }
  79.  
  80.             else {
  81.                 $EndEvent = Get-WinEvent -MaxEvents 1 -ProviderName $EndProvider -FilterXPath $EndXPath
  82.             }
  83.        }
  84.  
  85.         catch {
  86.             if ($PhaseName -ne 'Citrix Profile Mgmt') {
  87.                 if ($StartProvider -eq 'Microsoft-Windows-Security-Auditing' -or $EndProvider -eq 'Microsoft-Windows-Security-Auditing' ) {
  88.                     "Could not find $PhaseName events (requires audit process tracking)"
  89.                 }
  90.                 else {
  91.                     "Could not find $PhaseName events"
  92.                 }
  93.                 Return
  94.             }
  95.         }
  96.  
  97.         $EventInfo = @{}
  98.  
  99.         if ($EndEvent) {
  100.             if ((($EndEvent).GetType()).Name -eq 'DateTime') {
  101.                 $Duration = New-TimeSpan -Start $StartEvent.TimeCreated -End $EndEvent
  102.                 $EventInfo.EndTime = $EndEvent
  103.             }
  104.             else {
  105.                 $Duration = New-TimeSpan -Start $StartEvent.TimeCreated -End $EndEvent.TimeCreated
  106.                 $EventInfo.EndTime = $EndEvent.TimeCreated
  107.             }
  108.         }
  109.         $Script:EventProperties = $StartEvent.Properties
  110.         $EventInfo.PhaseName = $PhaseName
  111.         $EventInfo.StartTime = $StartEvent.TimeCreated
  112.         $EventInfo.Duration = $Duration.TotalSeconds
  113.  
  114.         $PSObject = New-Object -TypeName PSObject -Property $EventInfo
  115.  
  116.         if ($EventInfo.Duration) {
  117.             $Script:Output += $PSObject
  118.         }
  119.     }
  120.  
  121.         $Script:Output = @()
  122.  
  123.         try {
  124.         $LogonEvent = Get-WinEvent -MaxEvents 1 -ProviderName Microsoft-Windows-Security-Auditing -FilterXPath @"
  125.        *[System[(EventID='4624')]]
  126.        and *[EventData[Data[@Name='TargetUserName']
  127.        and (Data=`"$UserName`")]]
  128.        and *[EventData[Data[@Name='TargetDomainName']
  129.        and (Data=`"$UserDomain`")]]
  130.        and *[EventData[Data[@Name='LogonType']
  131.        and (Data=`"2`" or Data=`"10`" or Data=`"11`")]]
  132.        and *[EventData[Data[@Name='ProcessName']
  133.        and (Data=`"C:\Windows\System32\winlogon.exe`")]]
  134. "@ -ErrorAction Stop
  135.         }
  136.         catch {
  137.             Throw 'Could not find EventID 4624 (Successfully logged on event) in the Windows Security log.'
  138.         }
  139.  
  140.         $Logon = New-Object -TypeName PSObject
  141.  
  142.         Add-Member -InputObject $Logon -MemberType NoteProperty -Name LogonTime -Value $LogonEvent.TimeCreated
  143.         Add-Member -InputObject $Logon -MemberType NoteProperty -Name FormatTime -Value (Get-Date -Date $LogonEvent.TimeCreated -UFormat %r)
  144.         Add-Member -InputObject $Logon -MemberType NoteProperty -Name LogonID -Value ($LogonEvent.Properties[7]).Value
  145.         Add-Member -InputObject $Logon -MemberType NoteProperty -Name WinlogonPID -Value ($LogonEvent.Properties[16]).Value
  146.         Add-Member -InputObject $Logon -MemberType NoteProperty -Name UserSID -Value ($LogonEvent.Properties[4]).Value
  147.  
  148.         $ISO8601Date = Get-Date -Date $Logon.LogonTime
  149.         $ISO8601Date = $ISO8601Date.ToUniversalTime()
  150.         $ISO8601Date = $ISO8601Date.ToString("s")
  151.  
  152.         $NPStartXpath = @"
  153.        *[System[(EventID='4688')
  154.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  155.        and *[EventData[Data[@Name='ProcessId']
  156.        and (Data=`'$($Logon.WinlogonPID)`')]]
  157.        and *[EventData[Data[@Name='NewProcessName']
  158.        and (Data='C:\Windows\System32\mpnotify.exe')]]
  159. "@
  160.  
  161.         $NPEndXPath = @"
  162.        *[System[(EventID='4689')
  163.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  164.        and *[EventData[Data[@Name='ProcessName']
  165.        and (Data=`"C:\Windows\System32\mpnotify.exe`")]]
  166. "@
  167.  
  168.         $ProfStartXpath = @"
  169.        *[System[(EventID='10')
  170.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  171.        and *[EventData[Data and (Data='$UserName')]]
  172. "@
  173.  
  174.         $ProfEndXpath = @"
  175.        *[System[(EventID='1')
  176.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  177.        and *[System[Security[@UserID='$($Logon.UserSID)']]]
  178. "@
  179.  
  180.         $UserProfStartXPath = @"
  181.        *[System[(EventID='1')
  182.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  183.        and *[System[Security[@UserID='$($Logon.UserSID)']]]
  184. "@
  185.  
  186.         $UserProfEndXPath = @"
  187.        *[System[(EventID='2')
  188.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  189.        and *[System[Security[@UserID='$($Logon.UserSID)']]]
  190. "@
  191.  
  192.         $GPStartXPath = @"
  193.        *[System[(EventID='4001')
  194.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  195.        and *[EventData[Data[@Name='PrincipalSamName']
  196.        and (Data=`"$UserDomain\$UserName`")]]
  197. "@
  198.  
  199.         $GPEndXPath = @"
  200.        *[System[(EventID='8001')
  201.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  202.        and *[EventData[Data[@Name='PrincipalSamName']
  203.        and (Data=`"$UserDomain\$UserName`")]]
  204. "@
  205.  
  206.         $GPScriptStartXPath = @"
  207.        *[System[(EventID='4018')
  208.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  209.        and *[EventData[Data[@Name='PrincipalSamName']
  210.        and (Data=`"$UserDomain\$UserName`")]]
  211.        and *[EventData[Data[@Name='ScriptType']
  212.        and (Data='1')]]
  213. "@
  214.  
  215.         $GPScriptEndXPath = @"
  216.        *[System[(EventID='5018')
  217.        and  TimeCreated[@SystemTime>='$ISO8601Date']]]
  218.        and *[EventData[Data[@Name='PrincipalSamName']
  219.        and (Data=`"$UserDomain\$UserName`")]]
  220.        and *[EventData[Data[@Name='ScriptType']
  221.        and (Data='1')]]
  222. "@
  223.  
  224.         $UserinitXPath = @"
  225.        *[System[(EventID='4688')
  226.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  227.        and *[EventData[Data[@Name='ProcessId']
  228.        and (Data=`'$($Logon.WinlogonPID)`')]]
  229.        and *[EventData[Data[@Name='NewProcessName']
  230.        and (Data='C:\Windows\System32\userinit.exe')]]
  231. "@
  232.  
  233.         $ShellXPath = @"
  234.        *[System[(EventID='4688')
  235.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  236.        and *[EventData[Data[@Name='SubjectLogonId']
  237.        and (Data=`'$($Logon.LogonID)`')]]
  238.        and *[EventData[Data[@Name='NewProcessName']
  239.        and (Data=`"C:\Program Files (x86)\Citrix\system32\icast.exe`" or Data=`"C:\Windows\explorer.exe`")]]
  240. "@
  241.  
  242.         $ExplorerXPath = @"
  243.        *[System[(EventID='4688')
  244.        and TimeCreated[@SystemTime > '$ISO8601Date']]]
  245.        and *[EventData[Data[@Name='SubjectLogonId']
  246.        and (Data=`'$($Logon.LogonID)`')]]
  247.        and *[EventData[Data[@Name='NewProcessName']
  248.        and (Data=`"C:\Windows\explorer.exe`")]]
  249. "@
  250.     }
  251.  
  252.     process {
  253.         Get-PhaseEvent -PhaseName 'Network Providers' -StartProvider 'Microsoft-Windows-Security-Auditing' -EndProvider 'Microsoft-Windows-Security-Auditing' `
  254.         -StartXPath $NPStartXpath -EndXPath $NPEndXPath
  255.  
  256.         if (Get-WinEvent -ListProvider 'Citrix Profile management' -ErrorAction SilentlyContinue) {
  257.  
  258.             Get-PhaseEvent -PhaseName 'Citrix Profile Mgmt' -StartProvider 'Citrix Profile management' -EndProvider 'Microsoft-Windows-User Profiles Service' `
  259.             -StartXPath $ProfStartXpath -EndXPath $ProfEndXpath
  260.         }
  261.  
  262.         Get-PhaseEvent -PhaseName 'User Profile' -StartProvider 'Microsoft-Windows-User Profiles Service' -EndProvider 'Microsoft-Windows-User Profiles Service' `
  263.         -StartXPath $UserProfStartXPath -EndXPath $UserProfEndXPath
  264.  
  265.         Get-PhaseEvent -PhaseName 'Group Policy' -StartProvider 'Microsoft-Windows-GroupPolicy' -EndProvider 'Microsoft-Windows-GroupPolicy' `
  266.         -StartXPath $GPStartXPath -EndXPath $GPEndXPath
  267.  
  268.         Get-PhaseEvent -PhaseName 'GP Scripts' -StartProvider 'Microsoft-Windows-GroupPolicy' -EndProvider 'Microsoft-Windows-GroupPolicy' `
  269.         -StartXPath $GPScriptStartXPath -EndXPath $GPScriptEndXPath
  270.  
  271.         if ($Script:EventProperties[3].Value -eq $true) {
  272.             if ($Script:Output[-1].PhaseName -eq 'GP Scripts') {
  273.                 $Script:Output[-1].PhaseName = 'GP Scripts (sync)'
  274.             }
  275.         }
  276.  
  277.         else {
  278.             if ($Script:Output[-1].PhaseName -eq 'GP Scripts') {
  279.                 $Script:Output[-1].PhaseName = 'GP Scripts (async)'
  280.             }
  281.         }
  282.  
  283.         Get-PhaseEvent -PhaseName 'Pre-Shell (Userinit)' -StartProvider 'Microsoft-Windows-Security-Auditing' -EndProvider 'Microsoft-Windows-Security-Auditing' `
  284.         -StartXPath $UserinitXPath -EndXPath $ShellXPath
  285.  
  286.         if ($CUDesktopLoadTime) {
  287.         Get-PhaseEvent -PhaseName 'Shell' -StartProvider 'Microsoft-Windows-Security-Auditing' -StartXPath $ExplorerXPath -CUAddition $CUDesktopLoadTime
  288.         }
  289.  
  290.         if ($Script:Output[-1].PhaseName -eq 'Shell' -or $Script:Output[-1].PhaseName -eq 'Pre-Shell (Userinit)') {
  291.         $TotalDur = "{0:N1}" -f (New-TimeSpan -Start $Logon.LogonTime -End $Script:Output[-1].EndTime | Select-Object -ExpandProperty TotalSeconds) `
  292.         + " seconds"
  293.         }
  294.  
  295.         else
  296.         {
  297.         $TotalDur = 'N/A'
  298.         }
  299.  
  300.         $Script:Output = $Script:Output | Sort-Object StartTime
  301.  
  302.         for($i=1;$i -le $Script:Output.length-1;$i++) {
  303.  
  304.             $Deltas = New-TimeSpan -Start $Script:Output[$i-1].EndTime -End $Script:Output[$i].StartTime
  305.             $Script:Output[$i] | Add-Member -MemberType NoteProperty -Name TimeDelta -Value $Deltas -Force
  306.         }
  307.  
  308.         $Deltas = New-TimeSpan -Start $Logon.LogonTime -End $Script:Output[0].StartTime
  309.         $Script:Output[0] | Add-Member -MemberType NoteProperty -Name TimeDelta -Value $Deltas -Force
  310.     }
  311.  
  312.     end {
  313.         Write-Host "User name:`t $UserName `
  314. Logon Time:`t $($Logon.FormatTime) `
  315. Logon Duration:`t $TotalDur"
  316.  
  317.         $Format = @{Expression={$_.PhaseName};Label="Logon Phase"}, `
  318.         @{Expression={'{0:N1}' -f $_.Duration};Label="Duration (s)"}, `
  319.         @{Expression={'{0:hh:mm:ss.f}' -f $_.StartTime};Label="Start Time"}, `
  320.         @{Expression={'{0:hh:mm:ss.f}' -f $_.EndTime};Label="End Time"}, `
  321.         @{Expression={'{0:N1}' -f ($_.TimeDelta | Select-Object -ExpandProperty TotalSeconds)};Label="Interim Delay"}
  322.         $Script:Output | Format-Table $Format -AutoSize
  323.  
  324.         Write-Host "Only synchronous scripts affect logon duration"
  325.     }
  326. }
Advertisement
Add Comment
Please, Sign In to add comment