Advertisement
henrydenhengst

Test StoreFront or NetScaler Gateway v.2

Aug 17th, 2015
1,624
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2.     .SYNOPSIS
  3.         Test StoreFront or NetScaler Gateway (integrated with StoreFront) and XenApp by launching one or more Published Applications.
  4.     .DESCRIPTION
  5.         This script launches an a Published Applications through StoreFront or NetScaler Gateway (integrated with StoreFront).
  6.  
  7.     For MONITORING purposes!
  8.  
  9.         It attempts to closely resemble what an actual user would do by:
  10.         -Opening Internet Explorer.
  11.         -Navigating directly to the Receiver for Web site or NetScaler Gateway portal.
  12.         -Entering Username and Password.
  13.         -Logging in.
  14.         -Clicking on the Application(s).
  15.         -Logging off the StoreFront site.
  16.        
  17.         You can use thie Script to verify your most important Applications load.
  18.  
  19.         You can also use this Script to verify that each of your servers is repsonding correctly.
  20.     To do this you would need to Publish an Application from each server.
  21.     For example, you could publish Task Manager (taskmgr.exe), from each server, and name it something like "Server 1 Task Manager", "Server 2 Task Manager", etc, etc.
  22.  
  23.         Requirements:
  24.         -Citrix Receiver installed in the default location.
  25.         -Must be launched from an Elevated Administrator console of PowerShell x86. The 64 Bit Powershell will not work since the script is using Citrix Reciever, which is 32 bit, to verify a lunch and logoff the session.
  26.         -No other sessions should be connected/running before running the script.
  27.         -SiteURL should be part of the Intranet Zone (or Internet Zone at Medium-Low security) in order to be able to download AND launch the ICA file. This can be done through a GPO.
  28.         -StoreFront 2.0 or higher or NetScaler Gateway, version 9.3 or higher.
  29.         -Changes in web.config under C:\inetpub\wwwroot\Citrix\<storename>Web\: autoLaunchDesktop to false, pluginAssistant to false.
  30.         -Currently works for desktops or already subscribed apps only.
  31.         -You can auto subscribe users to apps by setting "KEYWORDS:Auto" in the published app's description or make sure the apps have been subscribed to manually.
  32.     -This script does not support AppController at this time.
  33.     -In order for the script to interact with the ICO, it requires the following to be set in the registry:
  34.         -x64: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Citrix\ICA Client\CCM
  35.         -x86: HKEY_LOCAL_MACHINE\SOFTWARE\Citrix\ICA Client\CCM
  36.         -AllowLiveMonitoring REG_DWORD 1
  37.         -AllowSimulationAPI REG_DWORD 1
  38.  
  39.     .PARAMETER SiteURL
  40.         The complete URL of the StoreFront Receiver for Web site or NetScaler Gateway portal.
  41.     .PARAMETER UserName
  42.         The name of the user which is used to log on. Acceptable forms are down-level logon name or user principal name.
  43.     .PARAMETER Password
  44.         The password of the user which is used to log on.
  45.     .PARAMETER smtpServer
  46.         The SMTP Server to send email alerts to
  47.     .PARAMETER emailFrom
  48.         Email Address that the alerts will come from
  49.     .PARAMETER emailTo
  50.         Email Address to send the alerts to
  51.     .PARAMETER SleepBeforeLogoff
  52.         The time in seconds to sleep after clicking the resource and before logging off. Default is 5.
  53.     .PARAMETER NumberOfRetries
  54.         The number of retries when retrieving an element. Default is 30.
  55.     .PARAMETER LogFilePath
  56.         Directory path to where the log file will be saved. Default is SystemDrive\Temp.
  57.     .PARAMETER LogFileName
  58.         File name for the log file. By default, the script creates a log file named "SFLauncher.log".
  59.     .PARAMETER EmailAlertsLagTime
  60.         This sets the amount of time, in seconds, an alert email will be sent if the same error is encountered. For example, if Application 1 fails, and the script is set to run every 30 minutes, you can set this to something higher than 1800 so not to be notified every 30 minutes.
  61.     .PARAMETER TwoFactorAuth
  62.         The token or password used for two-factor authentication. This is used in the NetScaler Gateway portal.
  63.     .PARAMETER ResourceName
  64.         The display name(s) of the Published Application(s) to be launched. Just add the applications at the end of the command line. See the example for more info.
  65.     .PARAMETER TimeToWaitForApp
  66.         The amount of time, in seconds, to wait for the Application to launch
  67.     .PARAMETER TimeToWaitForLogoff
  68.         The amount of time, in seconds, to wait before issuing the Logoff Command        
  69.        
  70.     .EXAMPLE
  71.         SFLauncher.ps1 -SiteURL "http://storefront.domain.com" -UserName "domain1\User1" -Password "P4ssw0rd" -smtpServer "smtp.domain.com -emailFrom "XenAppMon@domain.com" -emailTo "email@domain.com" -LogFilePath C:\Logifles -LogFileName SFLauncher.log "Application 1" "Application 2"
  72.  
  73.         Description
  74.         -----------
  75.         Launches a sPublished Application using the parameters provided.
  76.     .LINK
  77.         UserName format used in StoreFront.
  78.         http://msdn.microsoft.com/en-us/library/windows/desktop/aa380525(v=vs.85).aspx#down_level_logon_name
  79.     .LINK
  80.         Change to autoLaunchDesktop.
  81.         http://support.citrix.com/proddocs/topic/dws-storefront-20/dws-configure-wr-view.html
  82.     .LINK
  83.         Change to logoffAction.
  84.         http://support.citrix.com/proddocs/topic/dws-storefront-20/dws-configure-wr-workspace.html
  85.     .LINK
  86.         Automating the launch of HDX sessions through StoreFront (and NetScaler Gateway integrated with StoreFront)
  87.         http://blogs.citrix.com/2014/06/12/scripting-update-automating-the-launch-of-hdx-sessions-through-storefront-and-netscaler-gateway-integrated-with-storefront/
  88.     .NOTES
  89.         Created using SFLauncher.ps1 originally written by Citrix Systems, Inc.
  90. #>
  91.  
  92. Param (
  93.     [Parameter(Mandatory=$true,Position=0)] [string]$SiteURL,
  94.     [Parameter(Mandatory=$true,Position=1)] [string]$UserName,
  95.     [Parameter(Mandatory=$true,Position=2)] [string]$Password,
  96.     [Parameter(Mandatory=$true,Position=3)] [string]$smtpServer,
  97.     [Parameter(Mandatory=$true,Position=4)] [string]$emailFrom,
  98.     [Parameter(Mandatory=$true,Position=5)] [string]$emailTo,
  99.     [Parameter(ValueFromRemainingArguments=$true)] $ResourceName,
  100.     [Parameter(Mandatory=$false)] [int]$SleepBeforeLogoff = 5,
  101.     [Parameter(Mandatory=$false)] [int]$NumberOfRetries = 10,
  102.     [Parameter(Mandatory=$false)] [string]$LogFilePath = "$($env:SystemDrive)\Temp\",
  103.     [Parameter(Mandatory=$false)] [string]$LogFileName = "SFLauncher.log",
  104.     [Parameter(Mandatory=$false)] [string]$TwoFactorAuth,
  105.     [Parameter(Mandatory=$false)] $EmailAlertsLagTime = "900",
  106.     [Parameter(Mandatory=$false)] $TimeToWaitForApp = "120",
  107.     [Parameter(Mandatory=$false)] $TimeToWaitForLogoff = "15"
  108. )
  109.  
  110. #Set-StrictMode -Version 2
  111. Set-Variable -Name NGLoginButtonId -Value "Log_On" -Option Constant -Scope Script
  112. Set-Variable -Name NGUserNameTextBoxName -Value "login" -Option Constant -Scope Script
  113. Set-Variable -Name NGPasswordTextBoxName -Value "passwd" -Option Constant -Scope Script
  114. Set-Variable -Name NGTwoFactorTextBoxName -Value "passwd1" -Option Constant -Scope Script
  115. Set-Variable -Name SFLoginButtonId -Value "loginBtn" -Option Constant -Scope Script
  116. Set-Variable -Name SFUsernameTextBoxId -Value "username" -Option Constant -Scope Script
  117. Set-Variable -Name SFPasswordTextBoxId -Value "password" -Option Constant -Scope Script
  118. Set-Variable -Name SFLogOffLinkId -Value "userdetails-logoff" -Option Constant -Scope Script
  119. Set-Variable -Name x64DLLPath -Value "C:\Program Files (x86)\Citrix\ICA Client" -Option Constant -Scope Script
  120. Set-Variable -Name x86DLLPath -Value "C:\Program Files\Citrix\ICA Client" -Option Constant -Scope Script
  121.  
  122. # Setting up log files
  123. [string]$PreviuosLogFile = $($LogFilePath.TrimEnd('\') + "\" + $LogFileName + "_PreviuosRun.log")
  124. [string]$AlertsEmailed = $($LogFilePath.TrimEnd('\') + "\" + $LogFileName + "_AlertsEmailed.log")
  125. [string]$CurrentAlerts = $($LogFilePath.TrimEnd('\') + "\" + $LogFileName + "_AlertsCurrent.log")
  126. [string]$AlertEmail = $($LogFilePath.TrimEnd('\') + "\" + $LogFileName + "_AlertsEmailTimeStamp.log")
  127. [string]$ErrorStyle = "style=""background-color: #000000; color: #FF3300;"""
  128. [string]$Script:LogFile=$($LogFilePath.TrimEnd('\') + "\$LogFileName")
  129.  
  130. function ScriptInfo {
  131. "=============Script Parameters=================" | LogMe -displaynormal
  132. "StoreFront / Netscaler Gateway URL: $SiteURL" | LogMe -displaynormal
  133. "User Name: $UserName" | LogMe -displaynormal
  134. "SMTP Server: $smtpServer" | LogMe -displaynormal
  135. "Email From Address: $emailFrom" | LogMe -displaynormal
  136. "Email To Address: $emailTo" | LogMe -displaynormal
  137. "Log File: $Script:LogFile" | LogMe -displaynormal
  138. "Number of Resources found in command line: " + $ResourceName.count | LogMe -displaynormal
  139. foreach($Resource in $ResourceName) {"Resource: '$Resource'" | LogMe -displaynormal}
  140. "Number of Seconds before sending repeat Email: $EmailAlertsLagTime" | LogMe -displaynormal
  141. "Number of Seconds to wait for the App to Launch: $TimeToWaitForApp" | LogMe -displaynormal
  142. "Number of Seconds to wait to send Logoff Command: $TimeToWaitForLogoff" | LogMe -displaynormal
  143. "Number of Seconds to wait before StoreFront Logoff: $SleepBeforeLogoff" | LogMe -displaynormal
  144. "===============================================" | LogMe -displaynormal
  145. }
  146.  
  147. function CheckforDLL {
  148. if ((test-path -Path $x64DLLPath) -eq "TRUE") {Set-Variable -Name DLLPath -Value "$x64DLLPath\WfIcaLib.dll" -Option Constant -Scope Script }
  149. elseif ((test-path -Path $x86DLLPath) -eq "TRUE") {Set-Variable -Name DLLPath -Value "$x86DLLPath\WfIcaLib.dll" -Option Constant -Scope Script }
  150. else {throw "WfIcaLib.dll cannot be found, is the Citrix Client installed in it's default location?"}
  151. }
  152.  
  153. function Create-ProgressBar($Activity,$Status){
  154.     Write-Progress -Activity $Activity -status $Status
  155. }
  156.  
  157. function Complete-ProgressBar($Activity,$Status){
  158.     Write-Progress -Activity $Activity -status $Status -Completed
  159. }
  160.  
  161. function Get-ICAClientVersion{
  162.     # ============================ #
  163.     # Get Client Version Function  #
  164.     # ============================ #
  165.     $ErrorActionPreference = "SilentlyContinue"
  166.     $ica = New-Object -ComObject 'Citrix.ICAClient'
  167.     if($ica) { return $ica.ClientVersion }
  168.     else { return 0 }
  169. }
  170.  
  171. function GetElapsedTime([datetime]$starttime) {
  172.     # ====================== #
  173.     # Time Elapsed Function  #
  174.     # ====================== #
  175.     $runtime = $(get-date) - $starttime
  176.     $retStr = [string]::format("{0} sec(s)", $runtime.TotalSeconds)
  177.     $retStr
  178. }
  179.  
  180. function CreateRegEntry ($RegPath,$RegName,$PropType,$Val){
  181.     # ===================== #
  182.     # Create Registry Item  #
  183.     # ===================== #
  184.     try {New-ItemProperty -Path $RegPath -Name $RegName -PropertyType $PropType -Value $Val -ErrorAction Stop}
  185.     catch {
  186.     $Script:RegError += $_.Exception.Message
  187.     $_.Exception.Message  | LogMe -error
  188.     }
  189. }
  190.  
  191. function ModifyRegEntry ($RegPath,$RegName,$Val){
  192.     # ===================== #
  193.     # Modify Registry Item  #
  194.     # ===================== #
  195.     try {Set-ItemProperty -Path $RegPath -Name $RegName -Value $Val -ErrorAction Stop}
  196.     catch {
  197.     $Script:RegError += $_.Exception.Message
  198.     $_.Exception.Message  | LogMe -error
  199.     }
  200. }
  201.  
  202. function CreateRegKey ($RegPath){
  203.     # ===================== #
  204.     # Create Registry Item  #
  205.     # ===================== #
  206.     try {New-Item -Path $RegPath -ErrorAction Stop}
  207.     catch {
  208.     $Script:RegError += $_.Exception.Message
  209.     $_.Exception.Message  | LogMe -error
  210.     }
  211. }
  212.  
  213. function CheckRegistry {
  214.     # Making sure Registry Entries exist
  215.     # If not, try to create or modify
  216.     # If they cannot be created or modified, logging an error
  217.     # and skipping ICA test
  218.     $Script:Activity="Checking Registry for Settings Required"
  219.     $Path = "HKLM:SOFTWARE\Citrix\ICA Client\CCM"
  220.     $TestRegPath = Get-ItemProperty -Path $Path -ErrorAction SilentlyContinue
  221.    
  222.     if (!$TestRegPath) {CreateRegKey $Path}
  223.    
  224.     $AllowLiveMonitoringName = "AllowLiveMonitoring"
  225.     $AllowSimulationAPIName = "AllowSimulationAPI"
  226.     $PropertyType = "DWORD"
  227.     $Value =  "1"
  228.     $AllowLiveMonitoring = Get-ItemProperty -Path $Path -Name $AllowLiveMonitoringName -ErrorAction SilentlyContinue
  229.     $AllowSimulationAPI = Get-ItemProperty -Path $Path -Name $AllowSimulationAPIName  -ErrorAction SilentlyContinue
  230.     if (!$AllowLiveMonitoring) {
  231.         "AllowLiveMonitoring does not exist, creating it" | LogMe -warning
  232.         CreateRegEntry $Path $AllowLiveMonitoringName $PropertyType $Value
  233.     } elseif ($AllowLiveMonitoring.AllowLiveMonitoring -ne "1") {
  234.         "AllowLiveMonitoring Value does not equal 1, setting to 1" | LogMe -warning
  235.         ModifyRegEntry $Path $AllowLiveMonitoringName $Value
  236.         }
  237.     if (!$AllowSimulationAPI) {
  238.         "AllowSimulationAPI does not exist, creating it" | LogMe -warning
  239.         CreateRegEntry $Path $AllowSimulationAPIName $PropertyType $Value
  240.     } elseif ($AllowSimulationAPI.AllowSimulationAPI -ne "1") {
  241.         "AllowSimulationAPI value exists but does not equal 1, setting to 1" | LogMe -warning
  242.         ModifyRegEntry $Path $AllowSimulationAPIName $Value
  243.     }
  244.     if ($Script:RegError -ne $Null) {
  245.         "Errors were encountered when trying to add or modify registry entries required for this script to work" | LogMe -error
  246.         "You will either need to run this script once as an Adminitrator or create the following registry entries manually:" | LogMe -error
  247.         "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Citrix\ICA Client\CCM, AllowLiveMonitoring, DWORD, 1" | LogMe -error
  248.         "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Citrix\ICA Client\CCM, AllowLiveMonitoring, DWORD, 1" | LogMe -error
  249.     }
  250. }
  251.  
  252. function Send-Email {
  253.     #=============================================================================================
  254.     #                                 Email Section
  255.     #=============================================================================================  
  256.     $CurrTime = Get-Date -format g
  257.     $Script:Activity="Sending Email, if needed"
  258.     If (($Script:NewAlerts -eq $True) -or ($Script:SendEmail -eq $True)) {
  259.         if (Test-Path $AlertsEmailed) { clear-content $AlertsEmailed }
  260.         foreach ($line in $script:ErrorMessage) { $Line | Add-Content $AlertsEmailed }
  261.         # Setting MailFlag for the validation and error handling
  262.         $MailFlag = $True
  263.         If(!$emailFrom) { $MailFlag = $False; Write-Warning "From Email is NULL" }
  264.         If(!$emailTo) { $MailFlag = $False; Write-Warning "To Email is NULL" }
  265.         If(!$smtpServer) { $MailFlag = $False; Write-Warning "SMTP Server is NULL" }
  266.         # $MailFlag = $True
  267.         # Send email only if From, To and SMTP adress are not null
  268.         if($MailFlag -match $False) {
  269.             "Email could not send as the email parameters (FROM/TO/SMTP) failed"  | LogMe -error
  270.         } else {
  271.             # Send email only if there is either an Error or Warning Detected
  272.             $msg = new-object System.Net.Mail.MailMessage
  273.             $msg.From=$emailFrom
  274.             $msg.to.Add($emailTo)
  275.             if($emailCC) { $msg.cc.add($emailCC) }
  276.             $msg.Subject="StoreFront Error Detected"
  277.             $msg.IsBodyHtml=$true
  278.             $msg.Body=$Script:ErrorMessage
  279.             #$msg.Attachments.Add($logfile)
  280.             $smtp = new-object System.Net.Mail.SmtpClient
  281.             $smtp.host=$smtpServer
  282.             Try {
  283.                 $smtp.Send($msg)
  284.                 "Email Sent" | LogMe -displaygreen
  285.             } Catch {
  286.                 "Error Sending Email. See Error Messages Below:" | LogMe -error
  287.                 "Error Message: " + $_.Exception.Message | LogMe -error
  288.                 "Error Item: " + $_.Exception.ItemName | LogMe -error
  289.                 }
  290.         Start-Sleep 3
  291.         $msg.Dispose()
  292.         if (Test-Path $AlertEmail) { clear-content $AlertEmail }
  293.         $CurrTime | Add-Content $AlertEmail
  294.         }
  295.     } else {
  296.     "Not sending an email since there were no new Errors detected" |LogMe -displaynormal
  297.     }
  298. }
  299.  
  300. function CheckForErrors {
  301.     # Checking to see if there were any Errors Detected
  302.     # If there were, update the CurrentAlerts Log File for later comparison
  303.     $Script:Activity="Checking for Errors"
  304.     if ($script:ErrorMessage -ne $Null) {
  305.         if (Test-Path $CurrentAlerts) { clear-content $CurrentAlerts }
  306.             foreach ($line in $script:ErrorMessage) {$Line | Add-Content $CurrentAlerts}
  307.             # Get Content from Alert Log File, we want the first line, which should be the previuos time stamp.
  308.         if (Test-Path $AlertEmail) {
  309.         $AlertFileTime = gc $AlertEmail -TotalCount 1 }
  310.         # Check to see if the Time Span for sending alerts has passed
  311.         if ($AlertFileTime){
  312.             $AlertTimeSpan = New-TimeSpan $AlertFileTime $(Get-Date -format g)
  313.             $AlertTimeDifference = $AlertTimeSpan.TotalSeconds
  314.                 if (!$AlertTimeDifference) { $Script:SendEmail = $True }
  315.                 if ($AlertTimeDifference -ge $EmailAlertsLagTime) {
  316.                     $Script:SendEmail = $True
  317.                     "Email Alerts lag Time is $EmailAlertsLagTime seconds"
  318.                     "Alerts last sent on $AlertFileTime or $AlertTimeDifference seconds ago"
  319.                 } else { $Script:SendEmail = $False }
  320.             }
  321.         if (!$AlertFileTime) { $Script:SendEmail = $True }
  322.         # Checking Alert Log Contents from last run for comparison
  323.         if (Test-Path $AlertsEmailed) { $AlertLogContents = gc $AlertsEmailed }
  324.         # Checking Current Errors and Warnings found this duration for comparison
  325.         if (Test-Path $CurrentAlerts) { $CurrentAlertsContents = gc $CurrentAlerts }
  326.         # If the Alerts Email Log is empty but the Current Log is not, there are new alerts.
  327.         If (!$AlertLogContents -and $CurrentAlertsContents) {
  328.             $Script:NewAlerts = $True
  329.             $Script:SendEmail = $True
  330.             "New Alerts Detected"  | LogMe -warning
  331.         } ElseIf ($AlertLogContents -and $CurrentAlertsContents -and $Script:SendEmail -ne $True ) {
  332.             # If the Alert Email Log and the Current Alert Log matches then there are most likely no new errors
  333.             $AlertsDiff = compare-object $CurrentAlertsContents $AlertLogContents | Measure
  334.                 If ($AlertsDiff.count -gt "0") {
  335.                     $Script:SendEmail = $True
  336.                     $Script:NewAlerts = $True
  337.                     "New Alerts Detected"  | LogMe -warning
  338.             } else {
  339.                 $Script:NewAlerts = $False
  340.                 "Existing Alerts Detected"  | LogMe -warning
  341.                 "Previous Alerts are the same as Existing Alerts and lag time not reached"  | LogMe -displaynormal
  342.                 "No NEW Alerts Detected"  | LogMe -displaynormal
  343.             }
  344.         }
  345.     } else {
  346.         if (Test-Path $CurrentAlerts) {
  347.             clear-content $CurrentAlerts}
  348.         }
  349. }
  350.  
  351. function KillProcess {
  352.     # Killing left over processes from Receiver so the script will work the next time it is executed
  353.     # This is really only needed when running as a scheduled task
  354.     # If these processes are allowed to remain the Connection fails after the second try
  355.     $Script:Activity="Killing Receiver Processes"
  356.     "Killing processes from Receiver so the script will work, existing processes will prevent the ICO from working" | LogMe -displaynormal
  357.     $KillApps = $True
  358.     if ($KillApps -eq $True){
  359.     try {kill -name wfcrun32 -Force -ErrorAction SilentlyContinue}
  360.     catch {$_.Exception.Message}
  361.     try {kill -name concentr -Force -ErrorAction SilentlyContinue}
  362.     catch {$_.Exception.Message}
  363.     try {kill -name redirector -Force -ErrorAction SilentlyContinue}
  364.     catch {$_.Exception.Message}
  365.     try {kill -name wfica32 -Force -ErrorAction SilentlyContinue}
  366.     catch {$_.Exception.Message}
  367.     try {kill -name receiver -Force -ErrorAction SilentlyContinue}
  368.     catch {$_.Exception.Message}
  369.     }
  370.     Start-Sleep -Seconds 3
  371. }
  372.  
  373. function Create-PreviuosRunLog {
  374.     # Creating Log file for previuos ran jobs
  375.     # File is cleared when it reaches 1MB
  376.     if (test-path $PreviuosLogFile) {
  377.         $size = Get-ChildItem $PreviuosLogFile
  378.         if ($size.length -ge 1048576) {clear-content $PreviuosLogFile}
  379.     }
  380.     $LogPattern = @("[SUCCESS]","[ERROR]","[WARNING]","[SCRIPT_START]","[SCRIPT_END]")
  381.     if (Test-Path $Script:LogFile) {Get-Content $Script:LogFile | add-Content $PreviuosLogFile}
  382. }
  383.  
  384. Function LogMe() {
  385.     #===================================================================== #
  386.     # Sends the results into a logfile as well as in the powershell window #
  387.     #===================================================================== #
  388.     Param( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $logEntry,
  389.        [switch]$displaygreen,
  390.        [switch]$error,
  391.        [switch]$warning,
  392.        [switch]$displaynormal,
  393.        [switch]$displayscriptstartend,
  394.        [switch]$justprogressbar
  395.        )
  396.    
  397.     $Status = $logEntry
  398.     if($error) {
  399.         $script:ErrorMessage += "<p $ErrorStyle>$logEntry<p>"
  400.         Write-Host "$logEntry" -Foregroundcolor Red; $logEntry = [DateTime]::Now.ToString("[MM/dd/yyy HH:mm:ss.fff]: ") + "[ERROR] $logEntry"
  401.         }
  402.     elseif($warning) { Write-Host "$logEntry" -Foregroundcolor Yellow; $logEntry = [DateTime]::Now.ToString("[MM/dd/yyy HH:mm:ss.fff]: ") + "[WARNING] $logEntry"}
  403.     elseif ($displaynormal) { Write-Host "$logEntry" -Foregroundcolor White; $logEntry = [DateTime]::Now.ToString("[MM/dd/yyy HH:mm:ss.fff]: ") + "[INFO] $logEntry" }
  404.     elseif($displaygreen) { Write-Host "$logEntry" -Foregroundcolor Green; $logEntry = [DateTime]::Now.ToString("[MM/dd/yyy HH:mm:ss.fff]: ") + "[SUCCESS] $logEntry" }
  405.     elseif($displayscriptstartend) { Write-Host "$logEntry" -Foregroundcolor Magenta; $logEntry = "[SCRIPT_STARTEND] $logEntry" }
  406.     elseif($justprogressbar) { $logEntry=$Null }
  407.     else { Write-Host "$logEntry"; $logEntry = "$logEntry" }
  408.     if ($logEntry -ne $null) {$logEntry | Out-File -FilePath $Script:LogFile -Append}
  409.     Create-ProgressBar $Script:Activity $Status
  410. }
  411.  
  412. function Wait-ForPageReady {
  413.     "Waiting for Internet Explorer to return Page Ready" | LogMe -displaynormal
  414.     $try = 1
  415.     do {
  416.     $Script:Activity="Waiting for Page Ready"
  417.     "Try #$try`: Waiting for Internet Explorer to return Page Ready" | LogMe -justprogressbar
  418.     Start-Sleep 5
  419.     $try++
  420.     }
  421.     until ($internetExplorer.ReadyState -eq 4 -or $try -gt 12)
  422.     if ($internetExplorer.ReadyState -ne 4) {
  423.         "Internet Explorer did not repsond Page Ready within time allotted" | LogMe -error
  424.         break
  425.         }
  426. }
  427.  
  428. function Open-InternetExplorer {
  429.     Param ([Parameter(Mandatory=$true)] [string]$SiteURL)
  430.     $Script:Activity="Opening Internet Explorer"
  431.     "Creating Internet Explorer Component Object Model (COM)" | LogMe -displaynormal
  432.     Start-Sleep -seconds 1
  433.     New-Variable -Name internetExplorer -Value (New-Object -ComObject "InternetExplorer.Application") -Scope Script
  434.     "Setting Internet Explorer visible" | LogMe -displaynormal
  435.     Start-Sleep -seconds 1
  436.     $internetExplorer.visible = $true
  437.     "Navigating to '$SiteURL'" | Logme -displaynormal
  438.     Start-Sleep -seconds 1
  439.     $internetExplorer.Navigate2($SiteURL)
  440.     "Waiting until the page is ready" | Logme -displaynormal
  441.     Wait-ForPageReady
  442.     "Accessing Document Object Model (DOM)" | Logme -displaynormal
  443.     Start-Sleep -seconds 1
  444.     New-Variable -Name document -Value $internetExplorer.Document -Scope Script
  445. }
  446.  
  447. function Test-LoginForm {
  448.     "Detecting NetScaler Gateway or StoreFront login form" | Logme -displaynormal
  449.     $Script:Activity="Detecting NetScaler Gateway or StoreFront login form"
  450.     start-sleep 1
  451.     $loginButton = $null
  452.     $try = 1
  453.     do {
  454.         $NGloginButton = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $NGLoginButtonId)
  455.         $SFloginButton = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFLoginButtonId)
  456.         if ($NGloginButton -ne $null -and $NGloginButton.GetType() -ne [DBNull]) {
  457.             "NETSCALER GATEWAY DETECTED"  | Logme -displaygreen
  458.             Start-Sleep -Seconds 1
  459.             New-Variable -Name isNG -Value $true -Scope Script
  460.             $loginButton = $NGloginButton
  461.             break
  462.         } elseif ($SFloginButton -ne $null -and $SFloginButton.GetType() -ne [DBNull]) {
  463.             "STOREFRONT DETECTED"  | Logme -displaygreen
  464.             Start-Sleep -Seconds 1
  465.             New-Variable -Name isNG -Value $false -Scope Script
  466.             $loginButton = $SFloginButton
  467.             break
  468.         } else {
  469.             "Try #$try`: Still detecting..." | LogMe -justprogressbar
  470.             Start-Sleep -Seconds 3
  471.             $try++
  472.         }
  473.     } until ($try -gt $NumberOfRetries)
  474.     if ($loginButton -eq $null -or $loginButton.GetType() -eq [DBNull]) {
  475.         "Log on button not found" | Logme -error
  476.         Start-Sleep -Seconds 1
  477.     }    
  478. }
  479.  
  480. function Submit-UserCredentials {
  481.     $Script:Activity="Submitting User Credentials"
  482.     if ($isNG) {
  483.         "Getting Log On button" | Logme -displaynormal
  484.         $loginButton = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $NGLoginButtonId)
  485.         Start-Sleep -Seconds 1
  486.         "Getting UserName textbox" | Logme -displaynormal
  487.         $userNameTextBox = @([System.__ComObject].InvokeMember(“getElementsByName”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $NGUserNameTextBoxName)) | where { $_.name -eq $NGUserNameTextBoxName }
  488.         Start-Sleep -Seconds 1
  489.         "Getting Password textbox" | Logme -displaynormal
  490.         $passwordTextBox = @([System.__ComObject].InvokeMember(“getElementsByName”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $NGPasswordTextBoxName)) | where { $_.name -eq $NGPasswordTextBoxName }
  491.         Start-Sleep -Seconds 1
  492.         if ($TwoFactorAuth) {
  493.             "Getting Two Factor Authentication textbox" | Logme -displaynormal
  494.             $twoFactorTextBox = @([System.__ComObject].InvokeMember(“getElementsByName”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $NGTwoFactorTextBoxName)) | where { $_.name -eq $NGTwoFactorTextBoxName }
  495.                 if ($twoFactorTextBox -ne $null) {
  496.                     "Setting Two Factor Authentication" | Logme -displaynormal
  497.                     $twoFactorTextBox.value = $TwoFactorAuth
  498.                     Start-Sleep -Seconds 1
  499.                 } else {"Two-factor authentication textbox not found" | Logme -error
  500.                         Start-Sleep -Seconds 1
  501.                         }
  502.         }
  503.     } else {
  504.         "Getting Login button" | Logme -displaynormal
  505.         $loginButton = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFLoginButtonId)
  506.         Start-Sleep -Seconds 1
  507.         "Getting UserName textbox" | Logme -displaynormal
  508.         $userNameTextBox = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFUsernameTextBoxId)
  509.         Start-Sleep -Seconds 1
  510.         "Getting Password textbox" | Logme -displaynormal
  511.         $passwordTextBox = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFPasswordTextBoxId)
  512.         Start-Sleep -Seconds 1
  513.     }
  514.     if ($userNameTextBox -ne $null -and $userNameTextBox.GetType() -ne [DBNull]) {
  515.         "Setting UserName '$UserName'" | Logme -displaynormal
  516.         $userNameTextBox.Value = $UserName
  517.         Start-Sleep -Seconds 1
  518.     } else {"UserName textbox not found" | Logme -error}
  519.     if ($passwordTextBox -ne $null -and $passwordTextBox.GetType() -ne [DBNull]) {
  520.         "Setting Password" | Logme -displaynormal
  521.         $passwordTextBox.Value = $Password
  522.         Start-Sleep -Seconds 1
  523.     } else {"Password textbox not found" | Logme -error}
  524.     if ($loginButton -ne $null -and $loginButton.GetType() -ne [DBNull]) {
  525.         "Clicking Log On button" | Logme -displaynormal
  526.         $loginButton.Click()
  527.         Start-Sleep -Seconds 1
  528.     } else {"Login button not found" | Logme -error
  529.             Start-Sleep -Seconds 1
  530.             }
  531. }
  532.  
  533. function Start-Resource {
  534.    
  535.     $Script:Activity="Getting Storefront resources page"
  536.     "Getting Storefront resources page" | Logme -displaynormal
  537.     Start-Sleep -Seconds 3
  538.     $try = 1
  539.     do {
  540.         $logoffLink = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFLogOffLinkId)
  541.         if ($logoffLink -ne $null -and $logoffLink.GetType() -ne [DBNull]) {
  542.             "Successfully found Storefront resources page" | LogMe -displaygreen
  543.             Start-Sleep -Seconds 1
  544.             break
  545.         } else {
  546.             "Try #$try`: Still looking..." | LogMe -justprogressbar
  547.             Start-Sleep -Seconds 3
  548.             $try++
  549.         }
  550.     } until ($try -gt $NumberOfRetries)
  551.     if ($logoffLink -eq $null -or $logoffLink.GetType() -eq [DBNull]) {
  552.         "StoreFront recources page not found, possible page loading issue or logon issue"  | Logme -error
  553.         Start-Sleep -Seconds 3
  554.         $Script:StoreFrontRP = $False
  555.     }
  556.     if ($Script:StoreFrontRP -ne $False){
  557.         foreach ($App in $ResourceName){
  558.         $ScriptActivity="Locating resource '$App'"
  559.         "Locating resource '$App'"  | Logme -displaynormal
  560.         Start-Sleep -Seconds 1
  561.         $try = 1
  562.         do {
  563.             $resource = @([System.__ComObject].InvokeMember(“getElementsByTagName”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, "img")) | where { $_.alt -eq $App }
  564.             if ($resource -ne $null) {
  565.                 "Successfully Located resource '$App'" | LogMe -displaygreen
  566.                 Start-Sleep -Seconds 1
  567.                 break
  568.             } else {
  569.                 "Try #$try`: Still Looking..." | LogMe -justprogressbar
  570.                 Start-Sleep -Seconds 3
  571.                 $try++
  572.         }
  573.     } until ($try -gt $NumberOfRetries)
  574.         if ($resource -eq $null) {
  575.         "The ResourceName specified, '$App', was not found" | LogMe -error
  576.         Start-Sleep -Seconds 1
  577.         "Either the App was mistyped on the command line or it is not visible on the Storefront main page" | LogMe -error
  578.         Start-Sleep -Seconds 1
  579.         $ResourceFound = $false
  580.         }
  581.         if ($ResourceFound -ne $false) {
  582.         $Script:Activity="Looking for existing ICA Connections"
  583.         $wficaBefore = @()
  584.         Get-Process wfica32 -ErrorAction SilentlyContinue | select id | % { $wficaBefore += $_.id }
  585.         if ($($wficaBefore.Count) -ge 1) {
  586.             $SkipApp = $true
  587.             "Found $($wficaBefore.Count) session(s) before clicking '$App'" | Logme -error
  588.             "The script will only work correctly when there are no existing connections" | Logme -error
  589.             "Sessions will be disconnected when Receiver is killed at the end of the script and should work next time" | Logme -error
  590.             Start-Sleep -Seconds 1
  591.             throw("Found $($wficaBefore.Count) session(s) before clicking '$App'")
  592.             }
  593.         else {
  594.             $SkipApp = $false
  595.             "Found $($wficaBefore.Count) session(s) before clicking '$App'"  | Logme -displaynormal
  596.             Start-Sleep -Seconds 1
  597.             "Clicking resource '$App'" | Logme -displaynormal
  598.             Start-Sleep -Seconds 1
  599.             $LaunchTime = Get-Date
  600.             "Connect Started at $LaunchTime"  | Logme -displaygreen
  601.             $resource.Click()
  602.         }
  603.         $Script:Activity="Verifying that the session launched"
  604.         "Looking for connection info" | Logme -displaynormal
  605.         $wficaFound = $false
  606.         $try =1
  607.         do {
  608.             $wficaAfter = @()
  609.             Get-Process wfica32 -ErrorAction SilentlyContinue | select id | % { $wficaAfter += $_.id }
  610.             $wficaComparison = Compare-Object $wficaBefore $wficaAfter -PassThru
  611.             if ($wficaComparison -ne $null) {
  612.                 foreach ($wfica in $wficaComparison) {
  613.                     if ($wfica.SideIndicator -eq '=>') {
  614.                         $wficaFound = $true
  615.                         "Found $($wficaAfter.Count) sessions after clicking '$App'","Found wfica32.exe with PID $wfica for session launched"  | Logme -displaygreen                  
  616.                         break
  617.                     }
  618.                 }
  619.             }
  620.             if ($wficaFound -and $SkipApp -ne $True) {
  621.                 $index = $null
  622.                 "Waiting for '" + $App + "' to launch."   | Logme -displaynormal
  623.                 Do {
  624.                     try {Add-Type -Path $DLLPath}
  625.                         catch {throw "Error loading $DLLPath"}
  626.                     $ICO = New-Object WFICALib.ICAClientClass
  627.                     $ICO.OutputMode = [WFICALib.OutputMode]::OutputModeNormal
  628.                     $EnumHandle = $ICO.EnumerateCCMSessions()
  629.                     $NumSessions = $ICO.GetEnumNameCount($EnumHandle );
  630.                     $sessionid = $ICO.GetEnumNameByIndex($EnumHandle, $index)
  631.                     $ICO.StartMonitoringCCMSession($sessionid,$true)
  632.                     $APPSERVER = $ICO.GetSessionString(0)
  633.                     $null = $ICO.CloseEnumHandle($EnumHandle)
  634.                     $ICO.StopMonitoringCCMSession($sessionid)
  635.                     "Waiting to find an active XenApp Server for '$App'" | LogMe -justprogressbar
  636.                     Start-Sleep -Seconds 1
  637.                     $try++
  638.                     }
  639.                 until ($APPSERVER -or $try -gt $TimeToWaitForApp)
  640.                 if([string]::IsNullOrEmpty($APPSERVER) -and $SkipApp -ne $true) {
  641.                     "Unable to confirm that session launched for '$App'" | LogMe -error
  642.                     "The time to launch '$App' could have taken longer than $TimeToWaitForApp seconds" | LogMe -error
  643.                     }
  644.             else {
  645.                 "Found an active XenApp Server for '$App'" | LogMe -displaygreen
  646.                 $logonelapsed = GetElapsedTime $LaunchTime
  647.                 Start-Sleep -Seconds 1
  648.                 "Time taken to launch App is: $logonelapsed"   | Logme -displaygreen
  649.                 Start-Sleep -Seconds 1
  650.                 $App + " appears to be connected to Server: " + $APPSERVER   | Logme -displaynormal
  651.                 Start-Sleep -Seconds 1
  652.                 try {Add-Type -Path $DLLPath}
  653.                     catch {throw "Error loading WfIcaLib.dll"}
  654.                 $ICO = New-Object WFICALib.ICAClientClass
  655.                 $ICO.OutputMode = [WFICALib.OutputMode]::OutputModeNormal
  656.                 $EnumHandle = $ICO.EnumerateCCMSessions()
  657.                 $NumSessions = $ICO.GetEnumNameCount($EnumHandle );
  658.                 "Number of ICA Sessions is: $NumSessions"  | Logme -displaygreen
  659.                 $sessionid = $ICO.GetEnumNameByIndex($EnumHandle, $index)
  660.                 "Session ID: " + $sessionid  | Logme -displaygreen
  661.                 "Active XenApp Server is: " + $APPSERVER   | Logme -displaygreen
  662.                 $ICO.StartMonitoringCCMSession($sessionid,$true)
  663.                 "Sleeping for $TimeToWaitForLogoff seconds before sending ICA Logoff Command"   | Logme -displaynormal
  664.                 Start-Sleep -Seconds $TimeToWaitForLogoff
  665.                 "Sending Logoff Command"  | Logme -displaynormal
  666.                 $ICO.Logoff()
  667.                 Start-Sleep -Seconds 15
  668.                 $null = $ICO.CloseEnumHandle($EnumHandle)
  669.                 $ICO.StopMonitoringCCMSession($sessionid)    
  670.                 }
  671.             break
  672.             }
  673.         else {
  674.             "Try #$try`: Still looking..." | LogMe -justprogressbar
  675.             Start-Sleep -Seconds 3
  676.             $try++
  677.             }
  678.         } until ($try -gt $NumberOfRetries)
  679.         if (-not $wficaFound) {
  680.             "Unable to confirm that session launched for '$App'" | LogMe -error
  681.             Start-Sleep -Seconds 1
  682.             }
  683.         }
  684.         }
  685.     }
  686. }
  687.  
  688. function Logoff-Storefront {
  689.     $Script:Activity="Logoff StoreFront"
  690.     if ($Script:StoreFrontRP -ne $False){
  691.         "Sleeping $SleepBeforeLogoff seconds before logging off Storefront" | Logme -displaynormal
  692.         Start-Sleep -Seconds $SleepBeforeLogoff
  693.         "Getting log off link" | LogMe -displaynormal
  694.         Start-Sleep -Seconds 3
  695.         $try = 1
  696.         do {    
  697.         $logoffLink = [System.__ComObject].InvokeMember(“getElementById”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $document, $SFLogOffLinkId)
  698.         if ($logoffLink -ne $null -and $logoffLink.GetType() -ne [DBNull]) {
  699.             "Found log off link" | LogMe -displaygreen
  700.             Start-Sleep -Seconds 1
  701.             break
  702.             }
  703.         else {
  704.             "Try #$try`: Still looking..." | LogMe -justprogressbar
  705.             Start-Sleep -Seconds 3
  706.             $try++
  707.             }
  708.     }
  709.         until ($try -gt $NumberOfRetries)
  710.         if ($logoffLink -eq $null -or $logoffLink.GetType() -eq [DBNull]) {
  711.         "Log off link not found" | Logme -error
  712.         Start-Sleep -Seconds 1
  713.         } else {
  714.             "Clicking log off link" | Logme -displaynormal
  715.             Start-Sleep -Seconds 1
  716.             $logoffLink.Click()
  717.         }
  718.     }
  719. }
  720.  
  721. try {
  722.     cls
  723.     $startTime = Get-Date
  724.     rm -path $($LogFilePath.TrimEnd('\') + "\$LogFileName") -force -EA SilentlyContinue
  725.     $Script:Activity = "Starting Script"
  726.     ""
  727.     ""
  728.     ""
  729.     ""
  730.     ""
  731.     ""
  732.     ""
  733.     ""
  734.     "**********  LAUNCHER SCRIPT START  **********" | Logme -displayscriptstartend
  735.     ""
  736.     ScriptInfo
  737.     "Checking for Citrix Cient DLL" | logMe -displaynormal
  738.     CheckforDLL
  739.     "Checking Citrix Client Verion"  | Logme -displaynormal
  740.     $ClientVersion = Get-ICAClientVersion
  741.     "Citrix Client Version: " + $ClientVersion  | Logme -displaynormal
  742.     KillProcess
  743.     CheckRegistry
  744.     if ($RegError -eq $Null) {
  745.         Open-InternetExplorer -SiteURL $SiteURL
  746.         Test-LoginForm
  747.         Submit-UserCredentials
  748.         Wait-ForPageReady
  749.         Start-Resource
  750.         Logoff-Storefront
  751.         }
  752. }
  753.  
  754. catch {
  755.     "Exception caught by script" | Logme -error
  756.     $Error1 = $_.ToString()
  757.     $Error1  | Logme -error
  758.     $Error2 = $_.InvocationInfo.PositionMessage
  759.     $Error2  | Logme -error
  760.     throw $_
  761. }
  762.  
  763. finally {  
  764.     if ($internetExplorer -is [System.__ComObject]) {
  765.         if ($internetExplorer | Get-Member 'Quit') {
  766.             "Quitting Internet Explorer" | Logme -displaynormal
  767.             Start-Sleep -Seconds 3
  768.             $internetExplorer.Quit()
  769.         }
  770.         "Releasing Internet Explorer Component Object Model (COM)" | Logme -displaynormal
  771.         Start-Sleep -Seconds 3
  772.         [System.Runtime.Interopservices.Marshal]::ReleaseComObject($internetExplorer) | Out-Null
  773.         Remove-Variable -Name internetExplorer
  774.     }
  775.     #Kill Receiver Processes, only needed when ran as a scheduled task
  776.     KillProcess
  777.     CheckForErrors
  778.     Send-Email
  779.     Complete-ProgressBar $Activity="Script End" $Status="Exiting"
  780.     Create-PreviuosRunLog
  781.     ""
  782.     "**********  LAUNCHER SCRIPT END  **********" | Logme -displayscriptstartend
  783.     ""
  784. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement