├── Citrix-Morning-Report-Git.ps1 ├── README.md └── ScriptHeadingTemplate.cmd /Citrix-Morning-Report-Git.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Version Control: 3 | 11/26/2018 -Added Event Viewer Function 4 | 11/27/2018 -Corrected Maint mode function 5 | 12/27/2018 -Added App-V Log checks 6 | 01/15/2019 -Performance improvements in Get-RDSGracePeriod and Check-AppVLogs 7 | 03/05/2019 -Updated Check-AppVLogs to work with App-V Scheduler 2.5 and 2.6 8 | 03/05/2019 -Updated Get-RDSGracePeriod to not warn on 0 days, since that's now a success condition with working RDS licensing 9 | 03/26/2019 -Added GPO Checks 10 | 04/08/2019 -Updated App-V Checks 11 | 06/19/2019 -updated GPO-Check function to include 'registered' for the get-brokermachine 12 | #> 13 | 14 | Param( 15 | [Parameter(Mandatory=$True,Position=1)] 16 | [string[]]$DeliveryControllers, 17 | [Parameter(Mandatory=$True)] 18 | [string]$LogDir, 19 | [string]$MaintTag = "None", 20 | #[ValidateSet($True,$False)] 21 | [Switch]$Email, 22 | [Switch]$LogOnly, 23 | [String]$SMTPserver, 24 | [string[]]$ToAddress, 25 | [string]$FromAddress 26 | ) 27 | 28 | cls 29 | asnp citrix* 30 | 31 | $script:bad=0 32 | 33 | #Defines log path 34 | $firstcomp = Get-Date 35 | $filename = $firstcomp.month.ToString() + "-" + $firstcomp.day.ToString() + "-" + $firstcomp.year.ToString() + "-" + $firstcomp.hour.ToString() + "-" + $firstcomp.minute.ToString() + ".txt" 36 | $outputloc = $LogDir + "\" + $filename 37 | 38 | $hostname = hostname 39 | 40 | Start-Transcript -Path $outputloc 41 | 42 | Write-Host "-" 43 | 44 | ############ List Unregistered Machines ########### 45 | Function ListUnregs 46 | { 47 | 48 | Write-Host "****************************************************" 49 | 50 | Foreach ($DeliveryController in $DeliveryControllers) 51 | { 52 | write-host "Unregistered Machines in " $DeliveryController ":" -ForegroundColor Green 53 | $unregs = Get-BrokerMachine -AdminAddress $DeliveryController -MaxRecordCount 5000 -PowerState On -PowerActionPending $false -RegistrationState Unregistered | Sort-Object DNSName 54 | foreach ($unreg in $unregs) 55 | { 56 | #write-host $unreg.dnsname 57 | if ($unreg.SummaryState -like 'Available' -or $unreg.SummaryState -like 'Unregistered') 58 | { 59 | 60 | Try 61 | { 62 | if (!($LogOnly)){New-BrokerHostingPowerAction -AdminAddress $DeliveryController -Action Reset -MachineName $unreg.HostedMachineName | Out-Null} 63 | Write-host $unreg.DNSName.Split(".",2)[0] " (Force Restarting)" 64 | } 65 | Catch 66 | { 67 | Write-host $unreg.DNSName.Split(".",2)[0] " (Unable to Force Restart)" 68 | } 69 | } 70 | else 71 | { 72 | Write-host $unreg.DNSName.Split(".",2)[0] " (Users Logged in, Can't Restart)" 73 | } 74 | 75 | } 76 | if ($unregs){$script:bad=1} 77 | Write-host " " 78 | }#End Foreach Delivery Group 79 | Write-Host "****************************************************" 80 | } 81 | ############ END List Unregistered Machines ########### 82 | 83 | ############ List Powered Off Machines ########### 84 | Function ListOff 85 | { 86 | 87 | Write-Host "****************************************************" 88 | 89 | Foreach ($DeliveryController in $DeliveryControllers) 90 | { 91 | write-host "Powered Off Machines in " $DeliveryController ":" -ForegroundColor Green 92 | $poffs = Get-BrokerMachine -AdminAddress $DeliveryController -MaxRecordCount 5000 -PowerState Off -PowerActionPending $false -RegistrationState Unregistered | Sort-Object DNSName | Where-Object {($_.Tags -join(',')) -notlike "*$MaintTag*" -and $_.hostedmachinename -notlike 'ctxTEST*' -and $_.HostedMachineName -notlike 'CTXTST-*'} 93 | foreach ($poff in $poffs) 94 | { 95 | 96 | Try 97 | { 98 | 99 | if (!($LogOnly)){New-BrokerHostingPowerAction -Action TurnOn -MachineName $poff.HostedMachineName -AdminAddress $DeliveryController | Out-Null } 100 | Write-host $poff.DNSName.Split(".",2)[0] " (Powering On)" 101 | 102 | } 103 | Catch 104 | { 105 | Write-host $poff.DNSName.Split(".",2)[0] " (Unable to Turn On)" 106 | } 107 | } 108 | if ($poffs){$script:bad=1} 109 | Write-host " " 110 | } 111 | Write-Host "****************************************************" 112 | } 113 | ############ END List Powered Off Machines ########### 114 | 115 | ############ List Machines in Maint Mode ########### 116 | Function MaintMode 117 | { 118 | Write-Host "****************************************************" 119 | Foreach ($DeliveryController in $DeliveryControllers) 120 | { 121 | write-host "Machines in Maint Mode in " $DeliveryController ":" -ForegroundColor Green 122 | $maints = Get-BrokerDesktop -AdminAddress $DeliveryController -MaxRecordCount 5000 -IsPhysical $False | Sort-Object DNSName | Where-Object {$_.HostedMachineName -notlike 'CTXTST-*'} 123 | foreach ($maint in $maints) 124 | { 125 | if ($maint.Tags -like "$MaintTag*") 126 | { 127 | Write-host $maint.DNSName.Split(".",2)[0] "(Tagged for Maintenance Mode)" 128 | if (!($LogOnly)) 129 | { 130 | Try 131 | { 132 | Set-BrokerMachine -MachineName $maint.MachineName -InMaintenanceMode $True 133 | } 134 | Catch 135 | { 136 | Write-host $maint.DNSName.Split(".",2)[0] "(Unable to Enable Maintenance Mode)" 137 | } 138 | } 139 | if ($maint){$script:bad = '1'} 140 | } 141 | elseif ($maint.Tags -notcontains "$MaintTag*" -and $maint.InMaintenanceMode -eq "True") 142 | { 143 | Write-host $maint.DNSName.Split(".",2)[0] " (Disabling Maint Mode)" 144 | if (!($LogOnly)) 145 | { 146 | 147 | Try 148 | { 149 | Set-BrokerMachine -MachineName $maint.MachineName -InMaintenanceMode $false 150 | } 151 | Catch 152 | { 153 | Write-host $maint.DNSName.Split(".",2)[0] "(Unable to Disable Maintenance Mode" 154 | } 155 | } 156 | } 157 | 158 | } 159 | Write-host " " 160 | } 161 | Write-Host "****************************************************" 162 | } 163 | ############ END List Machines in Maint Mode ########### 164 | 165 | ############ List Bad Power States ########### 166 | Function PowerState 167 | { 168 | Write-Host "****************************************************" 169 | 170 | Foreach ($DeliveryController in $DeliveryControllers) 171 | { 172 | write-host "Machines with Bad Power States in " $DeliveryController ":" -ForegroundColor Green 173 | $pstates = Get-BrokerDesktop -AdminAddress $DeliveryController -MaxRecordCount 5000 | Sort-Object DNSName 174 | foreach ($pstate in $pstates) 175 | { 176 | if ($pstate.PowerState -ne 'Off' -and $pstate.PowerState -ne 'On' -and $pstate.PowerState -ne 'Unmanaged') 177 | { 178 | Write-host $pstate.DNSName.Split(".",2)[0] $pstate.powerstate 179 | if ($pstates){$script:bad=1} 180 | } 181 | } 182 | 183 | Write-host " " 184 | } 185 | Write-Host "****************************************************" 186 | } 187 | ############ END List Bad Power States ########### 188 | 189 | ############ List Pending Updates ########### 190 | Function PendingUpdates 191 | { 192 | Write-Host "****************************************************" 193 | 194 | Foreach ($DeliveryController in $DeliveryControllers) 195 | { 196 | write-host "Machines with Pending Updates in " $DeliveryController ":" -ForegroundColor Green 197 | $pupdates = Get-BrokerMachine -AdminAddress $DeliveryController -MaxRecordCount 5000 -ProvisioningType MCS | Sort-Object DNSName 198 | foreach ($pupdate in $pupdates) 199 | { 200 | #Write-host $pupdate.DNSName.Split(".",2)[0] $pupdate.ImageOutOfDate 201 | if ($pupdate.ImageOutOfDate -eq $True) 202 | { 203 | Write-host $pupdate.DNSName.Split(".",2)[0] $pupdate.ImageOutOfDate 204 | if ($pupdates){$script:bad=1} 205 | } 206 | } 207 | 208 | Write-host " " 209 | } 210 | Write-Host "****************************************************" 211 | } 212 | ############ END List Pending Updates ########### 213 | 214 | ############ List Bad Up Time ########### 215 | Function UpTime 216 | { 217 | 218 | Write-Host "****************************************************" 219 | 220 | Foreach ($DeliveryController in $DeliveryControllers) 221 | { 222 | write-host "Machines with Bad Uptime in " $DeliveryController ":" -ForegroundColor Green 223 | $uptimes = Get-BrokerDesktop -AdminAddress $DeliveryController -MaxRecordCount 5000 -RegistrationState Registered | Where-Object PowerState -ne 'Unmanaged' | Sort-Object DNSName 224 | foreach ($uptime in $uptimes) 225 | { 226 | #Write-host $uptime.HostedMachineName 227 | if (Test-connection -ComputerName $uptime.DNSName -Count 1 -Quiet) 228 | { 229 | Try 230 | { 231 | 232 | #Write-host $uptime.HostedMachineName 233 | #Perform System Uptime Check 234 | $LastBoot = (Get-WmiObject -Class Win32_OperatingSystem -computername $uptime.DNSName).LastBootUpTime 235 | $WMIsysuptime = (Get-Date) - [System.Management.ManagementDateTimeconverter]::ToDateTime($LastBoot) 236 | $WMIdays = $WMIsysuptime.Days 237 | $WMIDaystoHours = ($WMIsysuptime.Days)*24 238 | $WMIhours = $WMIsysuptime.hours 239 | $WMITotalHours = $WMIDaystoHours + $WMIhours 240 | if ($WMITotalHours -igt 24 -and ($uptime.SummaryState -like 'Available')) 241 | { 242 | if (!($LogOnly)){New-BrokerHostingPowerAction -AdminAddress $DeliveryController -Action Reset -MachineName $uptime.HostedMachineName | Out-Null} 243 | Write-Host $uptime.DNSName.Split(".",2)[0] has been up for $WMITotalHours Hours " (Force Restarting)" 244 | $u++ 245 | 246 | if ($uptime){$script:bad = '1'} 247 | } 248 | Elseif ($WMITotalHours -igt 24 -and ($uptime.SummaryState -like 'InUse')) 249 | { 250 | Write-Host $uptime.DNSName.Split(".",2)[0] has been up for $WMITotalHours Hours " (Users Logged in, Can't Restart)" 251 | if ($uptime){$script:bad = '1'} 252 | } 253 | } 254 | Catch 255 | { 256 | write-host $uptime.DNSName.Split(".",2)[0] "(WMI Issues)" 257 | } 258 | 259 | } 260 | } 261 | Write-host " " 262 | } 263 | Write-Host "****************************************************" 264 | } 265 | ############ END List Bad Up Time ########### 266 | 267 | ############ List Delivery Group Stats ########### 268 | Function DGStats 269 | { 270 | 271 | Write-Host "****************************************************" 272 | 273 | Foreach ($DeliveryController in $DeliveryControllers) 274 | { 275 | write-host "Delivery Group Stats in " $DeliveryController ":" -ForegroundColor Green 276 | $DGs = Get-BrokerDesktopGroup -AdminAddress $DeliveryController 277 | foreach ($DG in $DGs) 278 | { 279 | Write-Host **** Name: $DG.Name **** 280 | Write-Host Sessions: $DG.Sessions 281 | Write-Host Maint: $DG.InMaintenanceMode 282 | Write-Host FuncLevel: $DG.MinimumFunctionalLevel 283 | Write-Host "-" 284 | } 285 | Write-host " " 286 | } 287 | Write-Host "****************************************************" 288 | } 289 | ############ END List Delivery Group Stats ########### 290 | 291 | ############ List Decoms ########### 292 | Function Decoms 293 | { 294 | Write-Host "****************************************************" 295 | 296 | Foreach ($DeliveryController in $DeliveryControllers) 297 | { 298 | write-host "Decoms in " $DeliveryController ":" -ForegroundColor Green 299 | $decoms = Get-BrokerMachine -AdminAddress $DeliveryController -MaxRecordCount 5000 | Sort-Object DNSName | Where-Object {($_.Tags -join(',')) -like "*Decom*"} 300 | foreach ($decom in $decoms) 301 | { 302 | 303 | Write-host $Decom.dnsname 304 | } 305 | if ($decoms){$script:bad=1} 306 | Write-host " " 307 | } 308 | Write-Host "****************************************************" 309 | } 310 | ############ END Decoms ########### 311 | 312 | ############ Load Eval ############ 313 | Function Reset-BadLoadEvaluators 314 | # Purpose: Some VDAs will come up from nightly reboot with Load Evaluator at 100% but 0 user sessions. These hosts will not take new sessions until this is reset, which can be done 315 | # with a restart of the Citrix Desktop Service, aka BrokerAgent. This function identifies VDAs that need this and restarts the service accordingly. 316 | { 317 | Write-Host "****************************************************`n" 318 | Write-Host "Checking for bad load evaluator data`n" -ForegroundColor Green 319 | Foreach ($DeliveryController in $DeliveryControllers) 320 | { 321 | # Evaluate current state: 322 | # Get-BrokerMachine -AdminAddress $DeliveryController -SessionSupport MultiSession -Property SessionCount,LoadIndex,DNSName | Sort-Object @{Expression="LoadIndex";Descending=$True},@{Expression="SessionCount";Descending=$True} 323 | Write-Host " " 324 | $badMachines = @() 325 | # Machines with 100% load evaluator and 0 sessions 326 | try { 327 | $badMachines = Get-BrokerMachine -AdminAddress $DeliveryController -SessionSupport MultiSession -Property SessionCount,LoadIndex,DNSName -ErrorAction Stop | Where-Object {($_.LoadIndex -eq 10000) -and ($_.SessionCount -eq 0)} | Select-Object -ExpandProperty DNSName 328 | } 329 | catch { 330 | Write-Host "Unable to get data from DDC: $DeliveryController" 331 | Break 332 | } 333 | if ($badMachines.Count -ne 0) { 334 | if (!$LogOnly) { 335 | Invoke-Command -ComputerName $badMachines {Restart-Service -Name BrokerAgent} 336 | $badOutput = $badMachines -join ", " 337 | Write-Host "Reset BrokerAgent service on VDAs:" 338 | Write-Host "$badOutput" 339 | } 340 | else { 341 | Write-Host "In logging mode - not taking action. Hosts in need of attention:" 342 | Write-Host "$badOutput" 343 | } 344 | if ($badmachines){$script:bad=1} 345 | } 346 | else { 347 | } 348 | Write-Host " " 349 | } 350 | Write-Host "****************************************************`n" 351 | } 352 | ######### END Load Eval ########### 353 | 354 | ########### Check Event Viewer ############ 355 | 356 | Function Check-EventViewer 357 | { 358 | Write-Host "****************************************************" 359 | 360 | Foreach ($DeliveryController in $DeliveryControllers) 361 | { 362 | write-host "Event Viewer Events in " $DeliveryController ":" -ForegroundColor Green 363 | 364 | $beforedate = $firstcomp.AddDays(-1) 365 | $events=0 366 | 367 | #List of EventIDs to search for 368 | $EventIDs = '1069' 369 | 370 | $VDAs = Get-BrokerDesktop -AdminAddress $DeliveryController -MaxRecordCount 5000 -RegistrationState Registered -IsPhysical $False | Sort-Object DNSName 371 | Foreach ($VDA in $VDAs) 372 | { 373 | foreach ($EventID in $EventIDs) 374 | { 375 | #$CheckSysEvents = Get-EventLog -ComputerName $vda.DNSName.Split(".",2)[0] -LogName 'System' -Newest 1 -InstanceId $EventID -After $beforedate -ErrorAction SilentlyContinue 376 | $CheckSysEvents = Get-WinEvent -ComputerName $vda.DNSName.Split(".",2)[0] -MaxEvents 1 -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -FilterHashtable @{ LogName = "System"; StartTime = $beforedate; ID = $EventID} 377 | if ($CheckSysEvents) 378 | { 379 | if ($CheckSysEvents.ID -eq '1069') 380 | { 381 | Write-host Name: $vda.DNSName.Split(".",2)[0] EventID: $CheckSysEvents.ID Message: $CheckSysEvents.Message 382 | 383 | } 384 | $events++ 385 | } 386 | } 387 | } 388 | 389 | if ($events){$script:bad=1} 390 | Write-host " " 391 | } 392 | Write-Host "****************************************************" 393 | } 394 | 395 | ########### END Check Event Viewer ######## 396 | 397 | ############ Copy MOVE Log ########### 398 | Function Get-MoveLogs 399 | { 400 | 401 | Write-Host "****************************************************" 402 | write-host "Running MOVE Log function (Only executes on Sunday), Share = \\NAS\Share" -ForegroundColor Green 403 | if ($firstcomp.DayOfWeek -like 'Sunday') 404 | { 405 | 406 | $MOVELog = "\\nas\share\Citrix\Logs\MOVE\" + $firstcomp.Year + "-" + $firstcomp.Month + "-" + $firstcomp.Day + "-" + "McafeeMOVEScans.csv" 407 | Copy-Item -Path \\servername\reports\McAfeeMOVEScans.csv -Destination $MOVELog -Force -Verbose 408 | } 409 | 410 | 411 | Write-Host "****************************************************" 412 | } 413 | ############ END Copy MOVE Log ########### 414 | 415 | ############ RDS Grace Period Check ########### 416 | Function Get-RDSGracePeriod 417 | { 418 | Foreach ($DeliveryController in $DeliveryControllers) 419 | { 420 | write-host "Check RDS Grace Period in" $DeliveryController ":" -ForegroundColor Green 421 | $RDSVMs = Get-BrokerMachine -AdminAddress $DeliveryController -MaxRecordCount 5000 -RegistrationState Registered | Where-Object {$_.PowerState -ne 'Unmanaged' -and $_.SessionSupport -like "MultiSession"} | Sort-Object DNSName 422 | Foreach ($RDSVM in $RDSVMs) 423 | { 424 | $vmName = $RDSVM.DNSName.Split(".",2)[0] 425 | Try 426 | { 427 | #$GracePeriod = Invoke-Command -ComputerName $RDSVM.DNSName.Split(".",2)[0] -ScriptBlock { 428 | # (Invoke-WmiMethod -PATH (gwmi -namespace root\cimv2\terminalservices -class win32_terminalservicesetting).__PATH -name GetGracePeriodDays).daysleft 429 | #} 430 | $GracePeriod = (Invoke-WmiMethod -Path (Get-WmiObject -Namespace "root\cimv2\terminalservices" -Class "Win32_TerminalServiceSetting" -ComputerName $vmName).__PATH -Name GetGracePeriodDays).DaysLeft 431 | If ($GracePeriod -ilt '5' -and $GracePeriod -igt '0') 432 | { 433 | Write-host "$vmName Grace Period BAD - NEEDS ATTENTION ($GracePeriod)" 434 | if ($GracePeriod){$script:bad=1} 435 | } 436 | Else 437 | { 438 | #Write-host $RDSVM.DNSName.Split(".",2)[0] Grace Period Good $GracePeriod 439 | } 440 | } 441 | Catch 442 | { 443 | } 444 | 445 | } 446 | } 447 | 448 | Write-Host "****************************************************" 449 | } 450 | ############ END RDS Grace Period Check ########### 451 | 452 | ############ Check GPO Application ############ 453 | ## This function is reserved to check specific company type GPO settings upon boot ## 454 | Function Check-GPO 455 | { 456 | Write-Host "****************************************************`n" 457 | Write-Host "Checking for successful GPO application`n" -ForegroundColor Green 458 | 459 | Foreach ($DeliveryController in $DeliveryControllers) 460 | { 461 | #Skip certain Citrix Sites 462 | if ($DeliveryController -match "DeliveryControllerName") { 463 | Write-Verbose "Skipping check in Specific Site" 464 | Continue 465 | } 466 | $servers = (Get-BrokerMachine -AdminAddress $DeliveryController -RegistrationState Registered -SessionSupport MultiSession).HostedMachineName 467 | 468 | $runTime = (Get-Date -Format s).ToString().Replace(":","-") 469 | 470 | $objs = Invoke-Command -ComputerName $servers -ScriptBlock { 471 | 472 | # Checks 473 | $wc = Get-Item -Path "\\localhost\d$\vdiskdif.vhdx" 474 | $pfLastWrite = Get-ChildItem -Path "\\localhost\d$" -Force | Where-Object {$_.Name -eq "pagefile.sys"} | Select-Object -ExpandProperty LastWriteTime 475 | 476 | $obj = [pscustomobject]@{ 477 | HostName = $env:COMPUTERNAME 478 | WCTime = $wc.CreationTime 479 | PF = $pfLastWrite 480 | } 481 | 482 | Return $obj 483 | } 484 | 485 | $objs | Sort-Object HostName | Format-Table HostName,WCTime,PF | Out-File "\\NAS\Share\Citrix\Logs\BootChecks\BootChecks-$runTime.log" 486 | Write-Host "$DeliveryController results written to \\NAS\Share\Citrix\Logs\BootChecks\BootChecks-$runTime.log" 487 | } 488 | Write-Host "`n****************************************************`n" 489 | } 490 | 491 | ############ End Check GPO Application ############ 492 | 493 | ############ Check App-V Logs ############ 494 | Function Check-AppVLogs 495 | { 496 | $ErrorActionPreference = 'SilentlyContinue' 497 | Write-Host "****************************************************`n" 498 | Write-Host "Checking for App-V Scheduler log errors`n" -ForegroundColor Green 499 | Foreach ($DeliveryController in $DeliveryControllers) 500 | { 501 | $servers = Get-BrokerMachine -AdminAddress $DeliveryController -SessionSupport MultiSession 502 | #Skipping specific Delivery Controller 503 | if ($DeliveryController -match "DeliveryControllerName") { 504 | Write-Verbose "Skipping App-V check in DeliveryControllerName" 505 | Continue 506 | } 507 | 508 | foreach ($s in $servers) { 509 | $serverName = $s.HostedMachineName 510 | #Write-Host "Checking $serverName" 511 | try { 512 | $reachable = Test-Connection -ComputerName $serverName -Count 1 -Quiet 513 | if ($reachable) { 514 | # App-V 2.5 uses this name for the service 515 | $service25 = Get-Service -ComputerName $serverName -Name "AppV5SchedulerService" 516 | # App-V 2.6 uses this name for the service 517 | $service26 = Get-Service -ComputerName $serverName -Name "AppVSchedulerService" 518 | if (($service25 -eq $null) -and ($service26 -eq $null)) { 519 | Throw 520 | } 521 | } 522 | else { 523 | Write-Host "$serverName not reachable. Continuing." 524 | Continue 525 | } 526 | } 527 | catch { 528 | Write-Host "App-V Scheduler service not found on host $serverName" 529 | Continue 530 | } 531 | try { 532 | if ($service25) { 533 | # App-V 2.5 logs to this location 534 | $errorCount = (Get-WinEvent -ComputerName $serverName -FilterHashtable @{LogName='App-V 5 Scheduler';ProviderName='App-V 5 Scheduler Service';Id=0} | Where-Object {$_.Message -match "CoCreateInstance"}).Count 535 | if ($errorCount -gt 0) { 536 | Write-Host "App-V Errors logged on $serverName. Restarting service." 537 | if (!$LogOnly) {Invoke-Command -ComputerName $serverName -ScriptBlock {Restart-Service -Name AppV5SchedulerService}} 538 | } 539 | } 540 | elseif ($service26) { 541 | # App-V 2.6 logs to this location 542 | $errorCount = (Get-WinEvent -ComputerName $serverName -FilterHashtable @{LogName='App-V 5 Scheduler Agent';ProviderName='App-V 5 Scheduler Service';Id=0} | Where-Object {$_.Message -match "CoCreateInstance"}).Count 543 | if ($errorCount -gt 0) { 544 | Write-Host "App-V Errors logged on $servername. Restarting service." 545 | if (!$LogOnly) {Invoke-Command -ComputerName $serverName -ScriptBlock {Restart-Service -Name AppVSchedulerService}} 546 | } 547 | } 548 | } 549 | catch { 550 | Continue 551 | } 552 | } 553 | } 554 | Write-Host "" 555 | Write-Host "****************************************************`n" 556 | $ErrorActionPreference = 'Continue' 557 | } 558 | ############ END Check App-V Logs ############ 559 | 560 | ############ Email SMTP ########### 561 | Function Email 562 | { 563 | if ($script:bad -eq '1') 564 | { 565 | $results = (Get-Content -Path $outputloc -raw) 566 | } 567 | else 568 | { 569 | $results = "Citrix Morning Report is Clean. Check log for details ($LogDir)." 570 | } 571 | $smtpserver = $SMTPserver 572 | $msg = New-Object Net.Mail.MailMessage 573 | $smtp = New-Object net.Mail.SmtpClient($smtpserver) 574 | $msg.From = $FromAddress 575 | Foreach ($to in $Toaddress){$msg.To.Add($to)} 576 | $msg.Subject = "**Citrix Morning Report - $($DeliveryControllers)**" 577 | $msg.body = "$results" 578 | #$msg.Attachments.Add($att) 579 | $smtp.Send($msg) 580 | } 581 | 582 | ############ END Email SMTP ########### 583 | 584 | 585 | 586 | ###### Call out Functions ############ 587 | 588 | ListUnregs 589 | 590 | $now = Get-Date -Format s 591 | write-host "- $now" 592 | 593 | ListOff 594 | 595 | $now = Get-Date -Format s 596 | write-host "- $now" 597 | 598 | MaintMode 599 | 600 | $now = Get-Date -Format s 601 | write-host "- $now" 602 | 603 | PowerState 604 | 605 | $now = Get-Date -Format s 606 | write-host "- $now" 607 | 608 | PendingUpdates 609 | 610 | $now = Get-Date -Format s 611 | write-host "- $now" 612 | 613 | UpTime 614 | 615 | $now = Get-Date -Format s 616 | write-host "- $now" 617 | 618 | Decoms 619 | 620 | $now = Get-Date -Format s 621 | write-host "- $now" 622 | 623 | #DGStats 624 | 625 | Reset-BadLoadEvaluators 626 | 627 | $now = Get-Date -Format s 628 | write-host "- $now" 629 | 630 | #Check-EventViewer (disabling function now that we have the Get-RDSGracePeriod function) 631 | Get-RDSGracePeriod 632 | 633 | $now = Get-Date -Format s 634 | write-host "- $now" 635 | 636 | Get-MoveLogs 637 | 638 | $now = Get-Date -Format s 639 | write-host "- $now" 640 | 641 | Check-GPO 642 | 643 | $now = Get-Date -Format s 644 | write-host "- $now" 645 | 646 | Check-AppVLogs 647 | 648 | ####################### Get Elapsed Time of Script ########### 649 | $lastcomp = Get-date 650 | $diff = ($lastcomp - $firstcomp) 651 | 652 | Write-Host This Script took $diff.Minutes minutes and $diff.Seconds seconds to complete. 653 | Write-Host "This Script Runs at 4:00AM from ($hostname)" 654 | 655 | ############################################################## 656 | 657 | Stop-Transcript 658 | 659 | if ($Email) {Email} 660 | 661 | ###### END Call out Functions ############ 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Citrix-Morning-Report 2 | This script is something that can be scheduled to be run every morning to understand what the environment looks like. Also takes corrective actions if needed. 3 | 4 | Tested with XA/XD 7.15LTSR and 7.18, however this should work with pretty much all 7.x versions. 5 | 6 | Note: Use the -LogOnly option to run the script in Log Only mode, which doesn't take any actions on any machines. 7 | 8 | If you're looking for a Deep Dive video on overall use of this script, check out https://youtu.be/axpU49cNh3E 9 | 10 | # Prerequisites 11 | You can run this on a Delivery Controller or a machine that has Studio installed. See link for more information: https://developer-docs.citrix.com/projects/delivery-controller-sdk/en/latest/?_ga=2.136519158.731763323.1530151703-1594485461.1522783813#use-the-sdk 12 | 13 | # Functions 14 | ## Function ListUnregs 15 | This Function lists Unregistered Machines. 16 | 17 | ## Function ListOff 18 | This Function lists Powered Off machines. 19 | 20 | ## Function MaintMode 21 | This Function lists Machines in Maintenance Mode. Proactively disables maintnenace mode on machines. If machine has a 'Maintenance*' tag on it, it leave it in Maintenance mode. This has been added as a parameter for custom Tag names. Note: If you hvae a VDA in maintenance mode, but do not have it tagged, the script will take it out of maintenance mode. Also, if you have a machine tagged for Maintenance, but it's not actually in Maintenance Mode, the script will enable Maintenance Mode. 22 | 23 | ## Function PowerState 24 | This Function lists Machines that have a 'bad' Power State. An Example might be a Power State that is 'Unknown' to the hypervisor (hosting connection) or maybe stuck in a 'Turning On' state. Note: If you added the $MaintTag parameter, the script will not try to turn the VDA on. 25 | 26 | ## Function UpTime 27 | This Function lists Machines that haven't been restarted in a certain period of time. 28 | 29 | ## Function DGStats 30 | This Function lists Delivery Group statistics, including Name, # of Session, Maintenance Mode, and Functional Level 31 | 32 | ## Function Reset-BadLoadEvaluators 33 | This Function checks VDAs that come up from nightly reboot with Load Evaluator at 100% but 0 user sessions. These hosts will not take new sessions until this is reset. This function identifies VDAs that need this and restarts the service accordingly. 34 | 35 | ## Function Get-RDSGracePeriod 36 | This Function will check VDAs with RDS installed and confirm the RDS Grace Period is at 0, which means it has checked in with the RDS Licensing server and functioning correclty. 37 | 38 | ## Function Get-MoveLogs 39 | This Function copies over certain log files that you may need. In this case I'm copying over MOVE log files. Feel free to substitute whatever log file you need to copy. (Be sure to change the \\NAS\Share path). 40 | 41 | ## Function Check-AppVLogs 42 | This Function checks the VDA for App-V Scheduler service and checks the event viewer for certain errors that may indicate a problem. 43 | 44 | # 45 | Be Sure to comment out certain functions that aren't tailored to your environment. This is done at the bottom of the script. 46 | 47 | # Examples 48 | ``` 49 | .\Citrix-Morning-Report-Git.ps1 -DeliveryControllers xd7-dc01 -LogDir c:\temp -MaintTag "MaintenanceMode-Manual" 50 | ``` 51 | This Example runs the script on Delivery Controller 'xd7-dc01' and logs the results to 'C:\Temp'. It will also not take any action on machines tagged with the value of "MaintenanceMode-Manual". 52 | ``` 53 | .\Citrix-Morning-Report-Git.ps1 -DeliveryControllers xd7-dc01 -LogDir c:\temp -LogOnly 54 | ``` 55 | This Example puts the script in 'Log Mode' in which it will report everything, but won't take any action. Such as restarting Machines or Powering them on. 56 | ``` 57 | .\Citrix-Morning-Report-Git.ps1 -DeliveryControllers xd7-dc01 -LogDir c:\temp -Email -SMTPserver smtp.domain.local -ToAddress "Steve@adf.com","John@adf.com" -FromAddress Steve@adf.com 58 | ``` 59 | This uses the '-Email' Flag along with the SMTP Server and To/From Address 60 | -------------------------------------------------------------------------------- /ScriptHeadingTemplate.cmd: -------------------------------------------------------------------------------- 1 | #requires -version 3.0 2 | 3 | <# 4 | (Summarize purpose of the script) 5 | (Name of Creator) 6 | (Date Created) 7 | (Modification history:) 8 | (Date and Change Description) 9 | #> 10 | 11 | <# 12 | .SYNOPSIS 13 | (Summary of Script) 14 | 15 | .DESCRIPTION 16 | .PARAMETER (parameter1) 17 | (Enter details on how paraemter works/requirements) 18 | 19 | .PARAMETER (parameter2) 20 | (Enter details on how paraemter works/requirements) 21 | 22 | .EXAMPLE 23 | & '.\(Name of Script).ps1' -(Parameter1) 24 | (Enter Details on what the script will do with parameter details) 25 | 26 | .EXAMPLE 27 | & '.\(Name of Script).ps1' -(Parameter1) -(Paraemter2) 28 | (Enter Details on what the script will do with parameter details) 29 | 30 | .NOTES 31 | (Enter specific things to note for this script) 32 | #> --------------------------------------------------------------------------------