├── README.md ├── Netscaler Updater └── NS.csv ├── BGInfo ├── Admins.bgi ├── Admins.jpg ├── Bginfo.exe ├── Citrix.bgi ├── User.bgi ├── Bginfo64.exe ├── Background.jpg ├── Images │ ├── BGInfo.png │ └── BGInfo-Taskbar.png ├── Readme.md ├── BGInfo-Admins.ps1 ├── BGInfo-User.ps1 ├── BGInfo.ps1 └── BGInfo-Taskbar.ps1 ├── PVS Admin Toolkit.zip ├── PVS Admin Toolkit ├── WU.png ├── Exit.png ├── Logs.ico ├── PVSTK.ico ├── PVS │ ├── Devices.png │ ├── VDA.csv │ ├── Create PVS VM.ps1 │ └── Create PVS devices.ps1 ├── Configuration.png ├── PVSAdminToolkit.png ├── Hypervisor │ ├── Admin.png │ ├── Hypervisor.png │ └── Configure Hypervisor.ps1 ├── PVS Admin Toolkit.lnk ├── vDisk Merge │ ├── .DS_Store │ ├── Merge PVS vDisk.lnk │ ├── Merge PVS vDisk.png │ ├── Images │ │ └── PVS-merge.png │ └── Merge PVS vDisk.ps1 ├── Evergreen │ ├── Evergreen.ico │ ├── Evergreen.png │ └── Configure Evergreen.ps1 ├── vDisk Shrink │ ├── .DS_Store │ ├── sdelete64.exe │ ├── Images │ │ └── PVS-Shrink.png │ ├── Shrink PVS vDisk.lnk │ ├── Shrink PVS vDisk.png │ └── Shrink PVS vDisk.ps1 ├── vDisk Documentation │ ├── .DS_Store │ ├── Images │ │ └── PVSversions.png │ ├── PVS vDisk versions.lnk │ ├── PVS vDisk versions.png │ └── PVS vDisk versions.ps1 ├── vDisk Maintenance │ ├── BIS-F.xml │ ├── Scheduled Task.png │ ├── Windows Update.png │ ├── New PVS vDisk version.lnk │ ├── New PVS vDisk version.png │ ├── Promote PVS vDisk version.lnk │ ├── Promote PVS vDisk version.png │ ├── Evergreen-Template.xml │ ├── Windows Updates vDisk-Template.xml │ ├── Start Evergreen.ps1 │ ├── Start Windows Updates.ps1 │ ├── Windows Updates Task.ps1 │ ├── Evergreen Task.ps1 │ ├── New PVS vDisk version.ps1 │ ├── Promote PVS vDisk version.ps1 │ ├── Evergreen.ps1 │ └── Start Master.ps1 ├── vDisk Replication │ ├── .DS_Store │ ├── Replicate PVS vDisk.lnk │ ├── Replicate PVS vDisk.png │ ├── Images │ │ └── PVS-Replication.png │ └── Replicate PVS vDisk.ps1 ├── vDisk Export │ ├── Export PVS vDisk.png │ ├── Export PVS vDisk (XML).lnk │ └── Export PVS vDisk.ps1 ├── Remove logs.ps1 ├── Readme.md └── PVS Admin Toolkit.ps1 ├── Citrix Client notification ├── CWA.png ├── Images │ ├── HTML.png │ ├── Mac.png │ ├── Mail.png │ └── Mail2.png ├── README.md └── Citrix Client notification.ps1 ├── Teams Optimization check ├── Teams.png ├── Images │ ├── Teams 1.png │ └── Teams 2.png ├── README.md └── Check Teams optimization.ps1 └── BIS-F ├── SubCall └── BIS-F toast notification.ps1 └── BIS-F Personalization ready.ps1 /README.md: -------------------------------------------------------------------------------- 1 | Useful scripts for Citrix environments 2 | -------------------------------------------------------------------------------- /Netscaler Updater/NS.csv: -------------------------------------------------------------------------------- 1 | Name;IP 2 | NSLB01;172.27.10.112 3 | NSLB02;172.27.10.113 -------------------------------------------------------------------------------- /BGInfo/Admins.bgi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Admins.bgi -------------------------------------------------------------------------------- /BGInfo/Admins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Admins.jpg -------------------------------------------------------------------------------- /BGInfo/Bginfo.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Bginfo.exe -------------------------------------------------------------------------------- /BGInfo/Citrix.bgi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Citrix.bgi -------------------------------------------------------------------------------- /BGInfo/User.bgi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/User.bgi -------------------------------------------------------------------------------- /BGInfo/Bginfo64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Bginfo64.exe -------------------------------------------------------------------------------- /BGInfo/Background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Background.jpg -------------------------------------------------------------------------------- /PVS Admin Toolkit.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit.zip -------------------------------------------------------------------------------- /BGInfo/Images/BGInfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Images/BGInfo.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/WU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/WU.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Exit.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Logs.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Logs.ico -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVSTK.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/PVSTK.ico -------------------------------------------------------------------------------- /BGInfo/Images/BGInfo-Taskbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/BGInfo/Images/BGInfo-Taskbar.png -------------------------------------------------------------------------------- /Citrix Client notification/CWA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Citrix Client notification/CWA.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS/Devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/PVS/Devices.png -------------------------------------------------------------------------------- /Teams Optimization check/Teams.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Teams Optimization check/Teams.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Configuration.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVSAdminToolkit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/PVSAdminToolkit.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Hypervisor/Admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Hypervisor/Admin.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS Admin Toolkit.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/PVS Admin Toolkit.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Merge/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Merge/.DS_Store -------------------------------------------------------------------------------- /Citrix Client notification/Images/HTML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Citrix Client notification/Images/HTML.png -------------------------------------------------------------------------------- /Citrix Client notification/Images/Mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Citrix Client notification/Images/Mac.png -------------------------------------------------------------------------------- /Citrix Client notification/Images/Mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Citrix Client notification/Images/Mail.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Evergreen/Evergreen.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Evergreen/Evergreen.ico -------------------------------------------------------------------------------- /PVS Admin Toolkit/Evergreen/Evergreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Evergreen/Evergreen.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Shrink/.DS_Store -------------------------------------------------------------------------------- /Citrix Client notification/Images/Mail2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Citrix Client notification/Images/Mail2.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/Hypervisor/Hypervisor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/Hypervisor/Hypervisor.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/sdelete64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Shrink/sdelete64.exe -------------------------------------------------------------------------------- /Teams Optimization check/Images/Teams 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Teams Optimization check/Images/Teams 1.png -------------------------------------------------------------------------------- /Teams Optimization check/Images/Teams 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/Teams Optimization check/Images/Teams 2.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Documentation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Documentation/.DS_Store -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/BIS-F.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/BIS-F.xml -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Replication/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Replication/.DS_Store -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Merge/Merge PVS vDisk.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Merge/Merge PVS vDisk.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Merge/Merge PVS vDisk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Merge/Merge PVS vDisk.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Export/Export PVS vDisk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Export/Export PVS vDisk.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Merge/Images/PVS-merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Merge/Images/PVS-merge.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/Images/PVS-Shrink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Shrink/Images/PVS-Shrink.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/Shrink PVS vDisk.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Shrink/Shrink PVS vDisk.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/Shrink PVS vDisk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Shrink/Shrink PVS vDisk.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Scheduled Task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/Scheduled Task.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Windows Update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/Windows Update.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Export/Export PVS vDisk (XML).lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Export/Export PVS vDisk (XML).lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS/VDA.csv: -------------------------------------------------------------------------------- 1 | Hostname;IP;MAC 2 | VDA01;172.26.19.31;00:50:56:10:01:01 3 | VDA02;172.26.19.32;00:50:56:10:01:02 4 | VDA03;172.26.19.33;00:50:56:10:01:03 -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Replication/Replicate PVS vDisk.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Replication/Replicate PVS vDisk.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Replication/Replicate PVS vDisk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Replication/Replicate PVS vDisk.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Documentation/Images/PVSversions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Documentation/Images/PVSversions.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Documentation/PVS vDisk versions.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Documentation/PVS vDisk versions.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Documentation/PVS vDisk versions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Documentation/PVS vDisk versions.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/New PVS vDisk version.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/New PVS vDisk version.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/New PVS vDisk version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/New PVS vDisk version.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Replication/Images/PVS-Replication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Replication/Images/PVS-Replication.png -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Promote PVS vDisk version.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/Promote PVS vDisk version.lnk -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Promote PVS vDisk version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mohrpheus78/Citrix/HEAD/PVS Admin Toolkit/vDisk Maintenance/Promote PVS vDisk version.png -------------------------------------------------------------------------------- /BGInfo/Readme.md: -------------------------------------------------------------------------------- 1 | # BGInfo Powershell script and template 2 | 3 | This package contains the BGInfo64.exe, a BGI template file and two powershell scripts. 4 | The purpose of the scripts is to determine values, e.g. the size of the FSLogix container or the codec currently used in the Citrix session. These values are written into a specific registry key, which in turn is stored to a custom value and then displayed in the bginfo template. 5 | You can of course adapt and expand the scripts. The path to the files must be adapted in the scripts. 6 | You can display the information as a background image or as a tray icon in the systray which is displayed when required. The parameters for this differ in the two scripts. 7 | Execute the Posh scripts via logon script (GPO) or with the help of Citrix WEM as external task. Scripts must run in user context to get the values of the currently logged on user. Powershell.exe must be allowed for the users. 8 | 9 | ## Example 10 | ![BGInfo Taskbar](https://github.com/Mohrpheus78/Citrix/blob/main/BGInfo/Images/BGInfo-Taskbar.png) -------------------------------------------------------------------------------- /PVS Admin Toolkit/Evergreen/Configure Evergreen.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will configure Evergreen for installing software and updates inside a PVS vDisk 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to configure the famous Evergreen script from Manuel Winkel (@deyda) to be used with the PVS Admin Toolkit 7 | 8 | .NOTES 9 | 10 | Author: Dennis Mohrmann <@mohrpheus78> 11 | Creation Date: 2022-02-17 12 | Purpose/Change: 13 | #> 14 | 15 | # Variables 16 | $EvergreenConfig = "$PSScriptRoot\Evergreen.xml" 17 | $EvergreenSelection = New-Object PSObject 18 | 19 | Write-Host "======== Evergreen configuration ========" 20 | Write-Host `n 21 | 22 | Write-Host "You need a share where we can find the Evergreen script!" 23 | Write-Host `n 24 | $EvergreenShare = Read-Host "Enter a valid UNC path for the Evergreen Powershell script (\\server\share)" 25 | IF (!(Test-Path -Path "$EvergreenShare\Evergreen-Software Installer.ps1")) { 26 | Write-Host -ForegroundColor Red "Error, Evergreen.ps1 script not found! Check UNC path and run script again!" 27 | Read-Host "Press ENTER to exit" 28 | BREAK 29 | } 30 | Add-member -inputobject $EvergreenSelection -MemberType NoteProperty -Name "EvergreenShare" -Value $EvergreenShare -Force 31 | $EvergreenSelection | Export-Clixml $EvergreenConfig -------------------------------------------------------------------------------- /PVS Admin Toolkit/Remove logs.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will remove all logs file in the Logs folder if more than 30 items are present 4 | 5 | .DESCRIPTION 6 | 7 | .NOTES 8 | 9 | Version: 1.0 10 | Author: Dennis Mohrmann <@mohrpheus78> 11 | Creation Date: 2022-12-20 12 | #> 13 | 14 | $LogsCount = (Get-ChildItem -Path $PSScriptRoot\Logs| Measure-Object).Count 15 | IF ($LogsCount -gt 30) { 16 | 17 | # Remove logs? 18 | $title = "" 19 | $message = "The number of log files is more than 30, do you want to remove the logs?" 20 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 21 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 22 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 23 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 24 | 25 | switch ($choice) { 26 | 0 { 27 | $answer = 'Yes' 28 | } 29 | 1 { 30 | $answer = 'No' 31 | } 32 | } 33 | 34 | if ($answer -eq 'Yes') { 35 | Get-ChildItem -Path $PSScriptRoot\Logs | Remove-Item -Force 36 | Write-Host -ForegroundColor Yellow `n"$LogsCount log files successfully removed" 37 | Read-Host 38 | } 39 | else { 40 | Write-Host -ForegroundColor Yellow `n"Log file deletion canceled" 41 | Read-Host 42 | } 43 | } 44 | ELSE { 45 | Write-Host -ForegroundColor Yellow `n"Number of logs ($LogsCount) is below the threshold" 46 | Read-Host 47 | } 48 | -------------------------------------------------------------------------------- /BIS-F/SubCall/BIS-F toast notification.ps1: -------------------------------------------------------------------------------- 1 | # **************************************************** 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # Toast notification if BIS-F personalization is ready 4 | # 2/2 5 | # **************************************************** 6 | 7 | <# 8 | .SYNOPSIS 9 | This script is part of another script (BIS-F Personalization ready.ps1 )that calls this one. This script will show a toast notificaton to the currently logged in user, 10 | that BIS-F personalizationis ready. Use with Base Image Script Framework, place the script in a subfolder called SubCall in the folder 11 | "C:\Program Files (x86)\Base Image Script Framework (BIS-F)\Framework\SubCall\Personalization\Custom" 12 | 13 | .DESCRIPTION 14 | The script will first find out what locale settings the user has configured and then show the toast notification. 15 | 16 | .NOTES 17 | This script is part of the script "BIS-F Personalization ready.ps1" that calls this script. 18 | #> 19 | 20 | 21 | # Variables 22 | $Language = (Get-Culture).Name 23 | 24 | # Notification 25 | Add-Type -AssemblyName System.Windows.Forms 26 | $global:balloon = New-Object System.Windows.Forms.NotifyIcon 27 | $path = (Get-Process -id $pid).Path 28 | $balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path) 29 | $balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info 30 | IF ($Locale -eq "de-DE") { 31 | $balloon.BalloonTipText = 'Die Personalisierung ist abgeschlossen!'} # adjust text 32 | ELSE { 33 | $balloon.BalloonTipText = 'Personalization finished!'} # adjust text here 34 | $balloon.BalloonTipTitle = "Base Image Script Framework" 35 | $balloon.Visible = $true 36 | $balloon.ShowBalloonTip(15000) # adjust sec. -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Evergreen-Template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2021-11-18T08:56:47.3132691 5 | \Evergreen vDisk vDisk-Template 6 | 7 | 8 | 9 | 10 | S-1-5-21-2463503163-3906248725-1917044684-1130 11 | Password 12 | HighestAvailable 13 | 14 | 15 | 16 | IgnoreNew 17 | true 18 | false 19 | true 20 | false 21 | false 22 | 23 | true 24 | false 25 | 26 | true 27 | true 28 | false 29 | false 30 | false 31 | PT8H 32 | 7 33 | 34 | 35 | 36 | powershell.exe 37 | -ExecutionPolicy Bypass -NonInteractive -File "C:\Program Files (x86)\PVS Admin Toolkit\vDisk Maintenance\Start Evergreen.ps1" -vDiskName "vDisk-Template" -StoreName "Store-Template" -Task 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Windows Updates vDisk-Template.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2021-11-18T08:56:47.3132691 5 | \Windows Updates vDisk vDisk-Template 6 | 7 | 8 | 9 | 10 | S-1-5-21-2463503163-3906248725-1917044684-1130 11 | Password 12 | HighestAvailable 13 | 14 | 15 | 16 | IgnoreNew 17 | true 18 | false 19 | true 20 | false 21 | false 22 | 23 | true 24 | false 25 | 26 | true 27 | true 28 | false 29 | false 30 | false 31 | PT8H 32 | 7 33 | 34 | 35 | 36 | powershell.exe 37 | -ExecutionPolicy Bypass -NonInteractive -File "C:\Program Files (x86)\PVS Admin Toolkit\vDisk Maintenance\Start Windows Updates.ps1" -vDiskName "vDisk-Template" -StoreName "Store-Template" -Task 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /BIS-F/BIS-F Personalization ready.ps1: -------------------------------------------------------------------------------- 1 | # **************************************************** 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # Toast notification if BIS-F personalization is ready 4 | # 1/2 5 | # **************************************************** 6 | 7 | <# 8 | .SYNOPSIS 9 | This script will get the session ID of the currently logged in user and calls another script in the context of this user, to show a 10 | toast notification that BIS-F personalizationis ready. Use with Base Image Script Framework, place the script in the folder 11 | "C:\Program Files (x86)\Base Image Script Framework (BIS-F)\Framework\SubCall\Personalization\Custom", it will be launched by the BIS-F scheduled task at logon 12 | 13 | .DESCRIPTION 14 | The script will first find out what locale settings the user has configured and then show the toast notification 15 | 16 | .NOTES 17 | Edit the PSexec installation path 18 | #> 19 | 20 | # psexec location 21 | $psexec = "${env:ProgramFiles(x86)}\Sysinternals\psexec.exe" 22 | 23 | # Function to get the active user session 24 | Function Get-TSSessions { 25 | qwinsta | 26 | #Parse output 27 | ForEach-Object { 28 | $_.Trim() -replace "\s+",","} | 29 | #Convert to objects 30 | ConvertFrom-Csv 31 | } 32 | 33 | # Get session ID Console 34 | #$SessionID = (Get-TSSessions | Where-Object {$_.STATE -eq "Active" -and $_.SESSIONNAME -eq ">console"}).Id 35 | # Get session ID RDP 36 | #$SessionID = (Get-TSSessions | Where-Object {$_.STATE -eq "Active" -and $_.SESSIONNAME -like ">rdp*"}).Id 37 | $SessionID = (Get-TSSessions | Where-Object "STATE" -EQ "Active").ID 38 | 39 | # Lauch psexec in the context of the user to show the toast notification 40 | .$psexec -accepteula -s -i $SessionID powershell.exe -Executionpolicy bypass -file "${env:ProgramFiles(x86)}\Base Image Script Framework (BIS-F)\Framework\SubCall\Personalization\Custom\SubCall\BIS-F toast notification.ps1" -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Start Evergreen.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will launch the "New PVS vDisk script", start the master and execute the Evergreen software update script to install software updates inside the a new vDisk version 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to launch other scripts to execute Evergreen inside a new vDisk version 7 | 8 | 9 | .NOTES 10 | The variables have to be present in the XML files, configure Evergreen with the configuration menu first! 11 | 12 | Author: Dennis Mohrmann <@mohrpheus78> 13 | Creation Date: 2022-02-06 14 | Purpose/Change: 15 | 2022-02-17 Inital version 16 | #> 17 | 18 | param 19 | ( 20 | [Parameter(Mandatory = $false)] 21 | [ValidateNotNullOrEmpty()] 22 | [String]$vDiskName, 23 | 24 | [Parameter(Mandatory = $false)] 25 | [ValidateNotNullOrEmpty()] 26 | [String]$StoreName, 27 | 28 | [Parameter(Mandatory = $false)] 29 | [switch]$Task 30 | ) 31 | 32 | 33 | # Variables 34 | $Date = Get-Date -UFormat "%d.%m.%Y" 35 | $RootFolder = Split-Path -Path $PSScriptRoot 36 | $StartEvergreenLog = "$RootFolder\Logs\Start Evergreen.log" 37 | $Evergreen = "True" 38 | 39 | # Start logging 40 | Start-Transcript $StartEvergreenLog | Out-Null 41 | 42 | # RunAs Admin 43 | function Use-RunAs 44 | { 45 | # Check if script is running as Administrator and if not elevate it 46 | # Use Check Switch to check if admin 47 | 48 | param([Switch]$Check) 49 | 50 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 51 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 52 | 53 | if ($Check) { return $IsAdmin } 54 | 55 | if ($MyInvocation.ScriptName -ne "") 56 | { 57 | if (-not $IsAdmin) 58 | { 59 | try 60 | { 61 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 62 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 63 | } 64 | catch 65 | { 66 | Write-Warning "Error - Failed to restart script elevated" 67 | BREAK 68 | } 69 | exit 70 | } 71 | } 72 | } 73 | 74 | Use-RunAs 75 | 76 | # Launch script 77 | Write-Host -ForegroundColor Yellow "Executing Evergreen script inside a maintenance version" `n 78 | ."$PSScriptRoot\New PVS vDisk version.ps1" 79 | 80 | # Stop Logging 81 | Stop-Transcript | Out-Null 82 | $Content = Get-Content -Path $StartEvergreenLog | Select-Object -Skip 18 83 | Set-Content -Value $Content -Path $StartEvergreenLog 84 | Rename-Item -Path $StartEvergreenLog -NewName "Start-Evergreen-$vDiskName-$Date.log" -Force -EA SilentlyContinue 85 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Start Windows Updates.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will launch the "New PVS vDisk script", start the master and launch the Windows Update script to automatically install all avaialable windows updates on a device and will automatically reboot if needed. 4 | After reboot Windows updates will continue to run until no more updates are available. 5 | 6 | .DESCRIPTION 7 | The purpose of the script is to launch the Windows Update script 8 | 9 | .NOTES 10 | 11 | Author: Dennis Mohrmann <@mohrpheus78> 12 | Creation Date: 2022-02-06 13 | Purpose/Change: 14 | 2022-02-06 Inital version 15 | #> 16 | 17 | param 18 | ( 19 | [Parameter(Mandatory = $false)] 20 | [ValidateNotNullOrEmpty()] 21 | [String]$vDiskName, 22 | 23 | [Parameter(Mandatory = $false)] 24 | [ValidateNotNullOrEmpty()] 25 | [String]$StoreName, 26 | 27 | [Parameter(Mandatory = $false)] 28 | [switch]$Task 29 | ) 30 | 31 | 32 | # Variables 33 | $Date = Get-Date -UFormat "%d.%m.%Y" 34 | $RootFolder = Split-Path -Path $PSScriptRoot 35 | $WindowsUpdatesLog = "$RootFolder\Logs\Start Windows Update.log" 36 | $WindowsUpdates = "True" 37 | 38 | # Start logging 39 | Start-Transcript $WindowsUpdatesLog | Out-Null 40 | 41 | # RunAs Admin 42 | function Use-RunAs 43 | { 44 | # Check if script is running as Administrator and if not elevate it 45 | # Use Check Switch to check if admin 46 | 47 | param([Switch]$Check) 48 | 49 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 50 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 51 | 52 | if ($Check) { return $IsAdmin } 53 | 54 | if ($MyInvocation.ScriptName -ne "") 55 | { 56 | if (-not $IsAdmin) 57 | { 58 | try 59 | { 60 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 61 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 62 | } 63 | catch 64 | { 65 | Write-Warning "Error - Failed to restart script elevated" 66 | BREAK 67 | } 68 | exit 69 | } 70 | } 71 | } 72 | 73 | Use-RunAs 74 | 75 | # Launch script 76 | Write-Host -ForegroundColor Yellow "Installing Windows Updates into a maintenance version" `n 77 | ."$PSScriptRoot\New PVS vDisk version.ps1" -StartMaster 78 | 79 | # Stop Logging 80 | Stop-Transcript | Out-Null 81 | $Content = Get-Content -Path $WindowsUpdatesLog | Select-Object -Skip 18 82 | Set-Content -Value $Content -Path $WindowsUpdatesLog 83 | Rename-Item -Path $WindowsUpdatesLog -NewName "Start Windows Update-$MaintDeviceName-$Date.log" -Force -EA SilentlyContinue 84 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Export/Export PVS vDisk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will generate a XML export of your vDisk in the same folder. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to generate y XML backup file to be able to recreate a vDisk chain if you restore vDisk versions 7 | 8 | .EXAMPLE 9 | & '.\Export PVS vDisk.ps1' or use the shortcut 10 | 11 | .NOTES 12 | If you want to change the root folder you have to modify the shortcut. 13 | 14 | Author: Dennis Mohrmann <@mohrpheus78> 15 | Creation Date: 2021-11-06 16 | #> 17 | 18 | 19 | # RunAs Admin 20 | function Use-RunAs 21 | { 22 | # Check if script is running as Administrator and if not elevate it 23 | # Use Check Switch to check if admin 24 | 25 | param([Switch]$Check) 26 | 27 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 28 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 29 | 30 | if ($Check) { return $IsAdmin } 31 | 32 | if ($MyInvocation.ScriptName -ne "") 33 | { 34 | if (-not $IsAdmin) 35 | { 36 | try 37 | { 38 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 39 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 40 | } 41 | catch 42 | { 43 | Write-Warning "Error - Failed to restart script elevated" 44 | break 45 | } 46 | exit 47 | } 48 | } 49 | } 50 | 51 | Use-RunAs 52 | 53 | # Variables 54 | $RootFolder = Split-Path -Path $PSScriptRoot 55 | $Date = Get-Date -UFormat "%d.%m.%Y" 56 | $Log = "$RootFolder\Logs\Export PVS vDisks-$Date.log" 57 | 58 | # Start logging 59 | Start-Transcript $Log | Out-Null 60 | 61 | # PVS Powershell SnapIn laden 62 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 63 | try { Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop } 64 | catch { write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 65 | } 66 | 67 | Write-Host -Foregroundcolor Yellow "vDisk export running..." 68 | 69 | # Get PVS site 70 | $SiteName = (Get-PvsSite).SiteName 71 | 72 | # Get all vDisks and stores 73 | $AllvDisks = @(Get-PvsDiskInfo -SiteName $SiteName | Select-Object -Property Name, Storename) 74 | 75 | # Export (XML) all vDisks 76 | foreach ($vdisk in $AllvDisks) { 77 | Export-PvsDisk -DiskLocatorName $AllvDisks.Name -SiteName $SiteName -StoreName $AllvDisks.Storename 78 | } 79 | Write-Host -Foregroundcolor Green "ready, check logfile $log" 80 | 81 | # Stop Logging 82 | Stop-Transcript | Out-Null 83 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 84 | Set-Content -Value $Content -Path $Log 85 | 86 | Read-Host `n "Press ENTER to exit" 87 | -------------------------------------------------------------------------------- /Teams Optimization check/README.md: -------------------------------------------------------------------------------- 1 | # MS Teams optimization check 2 | First of all, I'm no powershell expert, so I'm sure there is room for improvements! 3 | 4 | This script will check if the MS Teams Citrix Optimization is working after starting Teams. After 25 sec. (launch time of Teams) the user gets a toast notificaton if the optimization is NOT active. A log for each client gets written to the "Logging" folder (which must exist with write permissions for users!). You need to create a shortcut for the user to launch the script. Replace the shortcut with the standard Teams shortcut. 5 | The script will first find the current session ID and the clientname of the user and what client platform/version is used in this session. The display language is determined to display the notification in the correct language. The toast notification appears longer than the default value (line 140). 6 | 7 | ## How To 8 | Attention: 9 | 10 | Requires a registry key on the VDA! 11 | ``` 12 | HKLM\Software\Citrix\HDXMediaStream 13 | Name: WebrtcDirectorIntegration 14 | Type: DWORD 15 | Value: 1 16 | ``` 17 | 18 | Requires the BurntToast Powershell Module! https://github.com/Windos/BurntToast 19 | Install the module on your Citrix VDA: 20 | ``` 21 | Install-Module -Name BurntToast 22 | ``` 23 | BurntToast needs an AppId to display the notifications, default is Windows Powershell. BurntToast will check the start menu for the shortcut, no message is shown if Powershell cannot be found. 24 | The script runs in the user context and in many cases admins hide the Powershell shortcuts from the start menu, so you have to define your own AppId. 25 | To define you own AppId you have to place a shortcut in the start menu and use this as your AppId. (e.g. a png file). The name of the AppId will be displayed at the bottom of the notification. 26 | To find out how to define the AppID, run 27 | ``` 28 | Get-StartApps 29 | ``` 30 | You get a list of possible values. Here you get more informations about the AppID: 31 | https://docs.microsoft.com/en-us/windows/win32/shell/appids 32 | https://toastit.dev/2018/02/04/burnttoast-appid-installer/ 33 | 34 | Place the script in a local folder on the VDA, together with the Teams.png file and a "Logging" folder with write permissions for the users. Run the script as a shortcut (replace with MS Teams shortcut) 35 | 36 | ## Execution 37 | Replace Teams shortcut with a custom shortcut. 38 | 39 | Example for WEM action: 40 | Command line: 41 | powershell.exe 42 | 43 | Working directory: 44 | C:\Program Files (x86)\Microsoft\Teams\current 45 | 46 | Parameters: 47 | -executionpolicy bypass -windowstyle hidden -file "C:\Program Files (x86)\Scripts\Check Teams optimization.ps1" 48 | 49 | ## Logging 50 | A log for each client gets written to the "Logging" folder (which must exist!). The log file will be overwritten. 51 | 52 | ## Examples 53 | ![Teams](https://github.com/Mohrpheus78/Citrix/blob/main/Teams%20Optimization%20check/Images/Teams%201.png) 54 | ![Notification](https://github.com/Mohrpheus78/Citrix/blob/main/Teams%20Optimization%20check/Images/Teams%202.png) 55 | 56 | 57 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Windows Updates Task.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will import a scheduled task from a template to start Windows Updates on a PVS maintenance device. 4 | 5 | .DESCRIPTION 6 | The script will first ask you about admin credentials to import the task and create a new task based on a template xml file. 7 | 8 | .EXAMPLE 9 | ."Windows Updates Task.ps1" 10 | 11 | .NOTES 12 | 13 | Author: Dennis Mohrmann <@mohrpheus78> 14 | Creation Date: 2021-11-18 15 | #> 16 | 17 | Write-Host -Foregroundcolor Yellow "Create a scheduled task to automatically install Windows Updates on your PVS vDisk"`n 18 | 19 | # Get Admin credentials 20 | $AdminUsername = Read-Host "Enter domain name and a domain admin user name to run the task (Domain\Admin or Admin@domain.com)" 21 | $AdminPassword = $password = Read-Host "Enter password" -AsSecureString 22 | $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $AdminUsername, $AdminPassword 23 | $Password = $Credentials.GetNetworkCredential().Password 24 | 25 | # Check if PVS SnapIn is available 26 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 27 | try { 28 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 29 | } 30 | catch { 31 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 32 | } 33 | 34 | # Get PVS SiteName 35 | $SiteName = (Get-PvsSite).SiteName 36 | 37 | # Get all vDisks 38 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 39 | 40 | # Add property "ID" to object 41 | $ID = 1 42 | $AllvDisks | ForEach-Object { 43 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 44 | $ID += 1 45 | } 46 | 47 | # Show menu to select vDisk 48 | Write-Host `n 49 | Write-Host "Available vDisks:" `n 50 | $ValidChoices = 1..($AllvDisks.Count) 51 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 52 | $Menu | Out-Host 53 | Write-Host 54 | $vDisk = Read-Host -Prompt 'Select the vDisk you want to update via task' 55 | 56 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 57 | if ($vDisk.ID -notin $ValidChoices) { 58 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 59 | Read-Host "Press any key to exit" 60 | BREAK 61 | } 62 | $vDiskName = $vDisk.Name 63 | $StoreName = $vDisk.StoreName 64 | 65 | (Get-Content "$PSScriptRoot\Windows Updates vDisk-Template.xml" ) | Foreach-Object { 66 | $_ -replace "vDisk-Template", "$vDiskName" ` 67 | -replace "Store-Template", "$StoreName" 68 | } | Set-Content "$PSScriptRoot\Windows Updates vDisk $vDiskName.xml" 69 | Try { 70 | Register-ScheduledTask -User "$AdminUsername" -Password "$Password" -Xml (Get-Content "$PSScriptRoot\Windows Updates vDisk $vDiskName.xml" | out-string) -TaskName "Windows Updates vDisk $vDiskName" -Force 71 | $Taskstate = (Get-ScheduledTask -TaskName "Windows Updates vDisk $vDiskName" | Select-Object State).State 72 | } 73 | catch { 74 | Write-Warning "Task state $Taskstate" 75 | write-warning "Error: $_." 76 | } 77 | Write-Host `n 78 | Write-Host -ForegroundColor Yellow "Add a trigger to the task 'Windows Updates vDisk $vDiskName', the vDisk will be promoted to 'Test' after installing the updates!"`n 79 | Read-Host "Press ENTER to exit" 80 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Evergreen Task.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will import a scheduled task from a template to launch Evergreen on a PVS maintenance device. 4 | 5 | .DESCRIPTION 6 | The script will first ask you about admin credentials to import the task and create a new task based on a template xml file. 7 | 8 | .EXAMPLE 9 | ."Evergreen Task.ps1" 10 | 11 | .NOTES 12 | Run as administrator! If you want to change the root folder you have to modify the shortcut. 13 | 14 | Author: Dennis Mohrmann <@mohrpheus78> 15 | Creation Date: 2022-02-18 16 | #> 17 | 18 | Write-Host -Foregroundcolor Yellow "Create a scheduled task to automatically launch the Evergreen script on your PVS vDisk"`n 19 | 20 | # Get Admin credentials 21 | $AdminUsername = Read-Host "Enter domain name and a domain admin user name to run the task (Domain\Admin or Admin@domain.com)" 22 | $AdminPassword = $password = Read-Host "Enter password" -AsSecureString 23 | $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $AdminUsername, $AdminPassword 24 | $Password = $Credentials.GetNetworkCredential().Password 25 | 26 | # Check if PVS SnapIn is available 27 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 28 | try { 29 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 30 | } 31 | catch { 32 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 33 | } 34 | 35 | # Get PVS SiteName 36 | $SiteName = (Get-PvsSite).SiteName 37 | 38 | # Get all vDisks 39 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 40 | 41 | # Add property "ID" to object 42 | $ID = 1 43 | $AllvDisks | ForEach-Object { 44 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 45 | $ID += 1 46 | } 47 | 48 | # Show menu to select vDisk 49 | Write-Host `n 50 | Write-Host "Available vDisks:" `n 51 | $ValidChoices = 1..($AllvDisks.Count) 52 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 53 | $Menu | Out-Host 54 | Write-Host 55 | $vDisk = Read-Host -Prompt 'Select the vDisk you want to update via task' 56 | 57 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 58 | if ($vDisk.ID -notin $ValidChoices) { 59 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 60 | Read-Host "Press any key to exit" 61 | BREAK 62 | } 63 | $vDiskName = $vDisk.Name 64 | $StoreName = $vDisk.StoreName 65 | 66 | (Get-Content "$PSScriptRoot\Evergreen-Template.xml" ) | Foreach-Object { 67 | $_ -replace "vDisk-Template", "$vDiskName" ` 68 | -replace "Store-Template", "$StoreName" 69 | } | Set-Content "$PSScriptRoot\Evergreen vDisk $vDiskName.xml" 70 | Try { 71 | Register-ScheduledTask -User "$AdminUsername" -Password "$Password" -Xml (Get-Content "$PSScriptRoot\Evergreen vDisk $vDiskName.xml" | out-string) -TaskName "Evergreen vDisk $vDiskName" -Force 72 | $Taskstate = (Get-ScheduledTask -TaskName "Evergreen vDisk $vDiskName" | Select-Object State).State 73 | } 74 | catch { 75 | Write-Warning "Task state $Taskstate" 76 | write-warning "Error: $_." 77 | } 78 | Write-Host `n 79 | Write-Host -ForegroundColor Yellow "Add a trigger to the task 'Evergreen vDisk $vDiskName', the vDisk will be promoted to 'Test' after installing the software!"`n 80 | Read-Host "Press ENTER to exit" 81 | -------------------------------------------------------------------------------- /BGInfo/BGInfo-Admins.ps1: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************************* 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # BGInfo powered by Powershell 4 | # 05/12/19 DM Initial release 5 | # 06/12/19 DM Added FSLogix 6 | # 09/12/19 DM Added deviceTRUST 7 | # 11/12/19 DM Initial public release 8 | # 11/12/19 DM Changed method to get session id 9 | # 18/06/20 DM Added MTU Size, WEM and VDA Agent version 10 | # 26/06/20 DM Added FSLogix Version 11 | # 26/06/20 DM Changed BGInfo process handling 12 | # 20/10/20 DM Added percent for FSL 13 | # 21/10/20 DM Added WEM Cache date 14 | # 09/11/20 DM Added Regkeys for IP and DNS (Standard method didn't work wirh Citrix Hypervisor) 15 | # ******************************************************************************************************* 16 | 17 | <# 18 | .SYNOPSIS 19 | Shows information about the user Citrix environment as BGInfo wallpaper 20 | 21 | .Description 22 | Execute as logon script or WEM external task to show useful informations about the user environment 23 | 24 | .EXAMPLE 25 | WEM: 26 | Path: powershell.exe 27 | Arguments: -executionpolicy bypass -file "C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo\BGInfo.ps1" 28 | .FSLogix Profile Size Warning.ps1 29 | 30 | .NOTES 31 | Execute as WEM external task (also after reconnect to refresh the information), logonscript or task at logon 32 | Edit the $BGInfoDir (Directory with BGInfo.exe) and $BGInfoFile (BGI file to load) 33 | #> 34 | 35 | # ******************* 36 | # Scripts starts here 37 | # ******************* 38 | 39 | # Source directory for BGInfo/BGInfo File (customize) 40 | $BGInfoDir = 'C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo' 41 | $BGInfoFile = 'Admins.bgi' 42 | 43 | # Regkey for setting the values (BGinfo gets informations from this source, don't edit!) 44 | $RegistryPath = "HKCU:\BGInfo" 45 | New-Item -Path $RegistryPath -EA SilentlyContinue 46 | 47 | # *************************** 48 | # Informations about Citrix # 49 | # *************************** 50 | # HDX Protocol 51 | $HDXProtocol = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Network_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Protocol 52 | New-ItemProperty -Path $RegistryPath -Name "HDX Protocol" -Value $HDXProtocol -Force 53 | 54 | # MTU 55 | $MTUSize = (ctxsession -v | findstr "EDT MTU:" | Select-Object -Last 1).split(":")[1].trimstart() 56 | New-ItemProperty -Path $RegistryPath -Name "MTU Size" -Value $MTUSize -Force 57 | 58 | # Rendezvous 59 | $Rendezvous = ((ctxsession -v | findstr "Rendezvous") | Select-Object -Last 1).split(":")[1].trimstart() 60 | New-ItemProperty -Path $RegistryPath -Name "Rendezvous" -Value $Rendezvous -Force 61 | 62 | # ******************** 63 | # General Informations 64 | # ******************** 65 | $IPAddress = (Get-NetIPConfiguration | Where-Object {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.status -ne "Disconnected"}).IPv4Address.IPAddress 66 | New-ItemProperty -Path $RegistryPath -Name "IPAddress" -Value $IPAddress -Force 67 | $DNSServer = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIPGateway -ne $null}).DNSServerSearchOrder 68 | New-ItemProperty -Path $RegistryPath -Name "DNSServer" -Value $DNSServer -Force 69 | 70 | 71 | # BGInfo # 72 | # Start BGInfo 73 | Start-Process -FilePath "$BGInfoDir\Bginfo64.exe" -ArgumentList @('/nolicprompt','/timer:0',"`"$BGInfoDir\$BGInfoFile`"") 74 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/Readme.md: -------------------------------------------------------------------------------- 1 | # Citrix PVS Admin Toolkit 2 | Useful scripts for your Citrix PVS environment, manage PVS with powershell. 3 | Put all files and folders to "C:\Program Files (x86)\PVS Admin Toolkit" on your PVS servers, start the main script (PVS Admin Toolkit.ps1) and launch all the other tasks from the systray icon. If you want to change the root folder of the scripts, you have to modify the shortcuts. 4 | 5 | 1. Configure your hypervisor, start "Hypervisor configuration" from the PVS Toolkit Configuration menu. Enter a IP address or hostname of your Citrix Xen host, VMWare vCenter/ESXi or Nutanix cluster and enter valid admin credentials to connect to the hypervisor, Nutanix is still in beta phase! 6 | 2. Launch "PVS configuration" from the PVS Toolkit Configuration menu to configure your PVS environment 7 | 3. Install the Powershell modules for your choosen hypervisor on your PVS server (Citrix XenServer SDK, VMWare Power.CLI or Nutanix.CLI) 8 | - https://www.citrix.com/downloads/citrix-hypervisor/product-software/hypervisor-82-standard-edition-CU1.html 9 | - https://developer.vmware.com/web/tool/vmware-powercli 10 | - https://portal.nutanix.com/page/documents/details?targetId=PS-Cmdlets-AOS-v6_0:ps-ps-cmdlets-installv2-r.html 11 | 4. Enable WMI on your PVS target device (master) and open the appropriate firewall ports (5985) 12 | 5. If you want to install Windows Updates inside your vDisk, install the "PSWindowsUpdate" Powershell module first on your PVS master (Install-Module -Name PSWindowsUpdate) 13 | 6. If you want to use the Evergreen script from Manuel Winkel (deyda) you have to configure a file share which contains the script, the software and an install list for your maintenance device. Download you software first with a seperate server, after that select the software you want to install and save the list in the following format: "NAME_OF_MASTER-Install.txt" (rename the LastSettings.txt file). For more information how to use Evergreen check Manuel's website: https://www.deyda.net/index.php/de/evergreen-script-de/ 14 | 15 | All values will be stored in XML files to be used as variables. Credentials will be encrypted and can only be used by the same user again. 16 | 17 | ## vDisk Maintenance 18 | The script will create a new vDisk version and promote this version to test or production mode. 19 | 20 | ## Windows Update 21 | The script will automatically install Windows Updates in the vDisk you selected, a new vDisk version will be created and the PVS maintenance device will be booted, after that Windows Updates will be installed and the VM is sealed and shut down with BIS-F if you use it. You can also create scheduled tasks to fully automate this process and install Windows Updates while you sleep :-). 22 | 23 | ## Evergreen 24 | The script will automatically install software and updates in the vDisk you selected with the great Evergreen script frpom Manuel Winkel. A new vDisk version will be created and the PVS maintenance device will be booted, after that software will be installed from a list (TXT file) and the VM is restarted, sealed and shut down with BIS-F if you use it. You can also create scheduled tasks to fully automate this process and use the Evergreen script while you sleep :-). 25 | ## vDisk Shrink 26 | The script will find all available vDisks and next find out what the latest merged base disk is (VHDX). After that the vDisk gets defragmented and shrinked. At the end you will see the vDisk size before and after shrinking. vDisk can't be in use while executing the script! Very useful after cleaning WinSXS folder with BIS-F for example. 27 | 28 | ## vDisk Documentation 29 | This script will generate a HTML report of your current vDisk versions and place it in a folder you define. 30 | 31 | ## vDisk Export 32 | This script will generate a XML export of your vDisk in the same folder. 33 | 34 | ## vDisk Replication 35 | This script will replicate a PVS vDisk with all version files to all other PVS servers that host this vDisk. 36 | 37 | ## vDisk Merge 38 | This script will merge a PVS vDisk you choose. 39 | 40 | # Example 41 | 42 | ![Toolkit](https://github.com/Mohrpheus78/Citrix/blob/main/PVS%20Admin%20Toolkit/PVSAdminToolkit.png) 43 | ![Toolkit](https://github.com/Mohrpheus78/Citrix/blob/main/PVS%20Admin%20Toolkit/WU.png) -------------------------------------------------------------------------------- /Citrix Client notification/README.md: -------------------------------------------------------------------------------- 1 | # Citrix client notification 2 | First of all, I'm no powershell expert, so I'm sure there is room for improvements! 3 | 4 | This script will check which Citrix client is installed on the endpoint (Platform and version). You define a minimum client version and if the clients endpoint version is lower, the user gets a toast notificaton that the client is out of date (or whatever you want). You can also inform the user that a HTML5 isn't supported. 5 | The script will first find the current session id of the user and what client platform/version is used inside this session. The display language is determined to display the notification in the correct language. The toast notification appears longer than the default vaulue (line 83). You can also change this value to "Short". 6 | 7 | ## How To 8 | Attention: Requires the BurntToast Powershell Module! https://github.com/Windos/BurntToast 9 | Use 10 | ``` 11 | Install-Module -Name BurntToast 12 | ``` 13 | to install the module on your Citrix VDA. 14 | 15 | BurntToast needs an AppId to display the notifications, default is Windows Powershell. BurntToast will check the start menu for the shortcut, no message is shown if Powershell cannot be found. 16 | The script runs in the user context and in many cases admins hide the Powershell shortcuts from the start menu, so you have to define your own AppId. 17 | To define you own AppId you have to place a shortcut in the start menu and use this as your AppId. (e.g. a png file). The name of the AppId will be displayed at the bottom of the notification. 18 | To find out how to define the AppID, run 19 | ``` 20 | Get-StartApps 21 | ``` 22 | You get a list of possible values. Here you get more informations about the AppID: 23 | https://docs.microsoft.com/en-us/windows/win32/shell/appids 24 | https://toastit.dev/2018/02/04/burnttoast-appid-installer/ 25 | 26 | Place the script in a local folder on the VDA, together with the CWA.png file and a "Logging" folder with write permissions for the users. Run the script as a logon script or with Citrix WEM external task. 27 | 28 | You can override the versions with these parameters: 29 | -WindowsClientMin "21.02.0.29" -MacClientMin "20.12.0.3" -LinuxClientMin "21.1.0.14" 30 | 31 | In a RDS environment you should configure the following group policies if you run logon scripts: 32 | 33 | **Administrative Templates > Computer Configuration** 34 | *System/Group Policy* 35 | Allow asynchronous user Group Policy processing when logging on through Remote Desktop Services: Enabled 36 | 37 | *System/Logon* 38 | Always wait for the network at computer startup and logon: Disabled 39 | 40 | *System/Scripts* 41 | Run startup scripts asynchronously: Disabled 42 | Run Windows PowerShell scripts first at user logon, logoff: Enabled 43 | ## Mail 44 | Use the Parameter MailButton to show the user a button which opens a predefined mail for the helpdesk, the drfault mailclient will be used 45 | -Mailbutton True or False 46 | ## Possible Citrix WorkspaceApp versions 47 | Of course there are more versions, these are examples! 48 | ##### Windows client CR versions 49 | 20.9.6.34 (2009.6), 20.10.0.20 (2010), 20.12.0.39 (2012), 20.12.1.42 (2012.1), 21.02.0.25 (2102) 50 | ##### Windows client LTSR version 51 | 19.12.3000.6 (19.12.3000.6) 52 | ##### Mac client versions 53 | 20.07.0.6 (2007), 20.08.0.3 (2008), 20.9.0.17 (2009), 20.10.0.16 (2010), 20.12.0.3 (2012), 21.02.0.29 (2102) 54 | ##### Linux client versions 55 | 20.9.0.15 (2009), 20.10.0.6 (2010), 21.1.0.14 (2011), 20.12.0.12 (2012) 56 | 57 | ## BurntToast parameters 58 | - $BTAppIcon defines the icon that will be used for the notification. 59 | - $BTAppID defines the AppID (must be present in the users start menu). You can use a dummy, but make sure you place a shortcut in the start menu first. 60 | - $BTAudio defines the sound (https://docs.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-audio) 61 | - Of course you can change the notification text, just change the $BTText1, $BTText2 and $BTText3 variables. 62 | You can also change the language with the $Language variable. 63 | 64 | ## Execution 65 | - Powershell logonscript 66 | Script Name: 67 | C:\Program Files (x86)\Scripts\Notifications\Citrix Client notification.ps1 68 | Script parameters: 69 | -WindowsClientMin "20.12.1.42" -MacClientMin "20.12.0.3" 70 | 71 | - WEM external task 72 | Path: powershell.exe 73 | Arguments: 74 | -executionpolicy bypass -file "C:\Program Files (x86)\Scripts\Citrix Client notification.ps1" 75 | 76 | ## Logging 77 | A log for each client gets written to the "Logging" folder (which must exist!). The log file will be overwritten. 78 | 79 | ## Examples 80 | ![HTML client](https://github.com/Mohrpheus78/Citrix/blob/main/Citrix%20Client%20notification/Images/HTML.png) 81 | ![MAC client](https://github.com/Mohrpheus78/Citrix/blob/main/Citrix%20Client%20notification/Images/Mac.png) 82 | ![MAC client](https://github.com/Mohrpheus78/Citrix/blob/main/Citrix%20Client%20notification/Images/Mail.png) 83 | ![MAC client](https://github.com/Mohrpheus78/Citrix/blob/main/Citrix%20Client%20notification/Images/Mail2.png) 84 | -------------------------------------------------------------------------------- /BGInfo/BGInfo-User.ps1: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************************* 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # BGInfo powered by Powershell 4 | # 05/12/19 DM Initial release 5 | # 06/12/19 DM Added FSLogix 6 | # 09/12/19 DM Added deviceTRUST 7 | # 11/12/19 DM Initial public release 8 | # 11/12/19 DM Changed method to get session id 9 | # 18/06/20 DM Added MTU Size, WEM and VDA Agent version 10 | # 26/06/20 DM Added FSLogix Version 11 | # 26/06/20 DM Changed BGInfo process handling 12 | # 20/10/20 DM Added percent for FSL 13 | # 21/10/20 DM Added WEM Cache date 14 | # 09/11/20 DM Added Regkeys for IP and DNS (Standard method didn't work wirh Citrix Hypervisor) 15 | # 06/19/23 DM Added Proxy for Rendezvous and user logon time 16 | # ******************************************************************************************************* 17 | 18 | <# 19 | .SYNOPSIS 20 | Shows information about the user Citrix environment as BGInfo wallpaper 21 | 22 | .Description 23 | Execute as logon script or WEM external task to show useful informations about the user environment 24 | 25 | .EXAMPLE 26 | WEM: 27 | Path: powershell.exe 28 | Arguments: -executionpolicy bypass -file "C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo\BGInfo.ps1" 29 | .FSLogix Profile Size Warning.ps1 30 | 31 | .NOTES 32 | Execute as WEM external task (also after reconnect to refresh the information), logonscript or task at logon 33 | Edit the $BGInfoDir (Directory with BGInfo.exe) and $BGInfoFile (BGI file to load) 34 | #> 35 | 36 | # ******************* 37 | # Scripts starts here 38 | # ******************* 39 | 40 | # Source directory for BGInfo/BGInfo File (customize) 41 | $BGInfoDir = 'C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo' 42 | $BGInfoFile = 'User.bgi' 43 | 44 | # Regkey for setting the values (BGinfo gets informations from this source, don't edit!) 45 | $RegistryPath = "HKCU:\BGInfo" 46 | New-Item -Path $RegistryPath -EA SilentlyContinue 47 | 48 | 49 | # ******************** 50 | # General Informations 51 | # ******************** 52 | $IPAddress = (Get-NetIPConfiguration | Where-Object {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.status -ne "Disconnected"}).IPv4Address.IPAddress 53 | New-ItemProperty -Path $RegistryPath -Name "IPAddress" -Value $IPAddress -Force 54 | $DNSServer = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIPGateway -ne $null}).DNSServerSearchOrder 55 | New-ItemProperty -Path $RegistryPath -Name "DNSServer" -Value $DNSServer -Force 56 | 57 | 58 | # *************************** 59 | # Informations about Citrix # 60 | # *************************** 61 | 62 | # Citrix SessionID 63 | $CitrixSessionID = Get-ChildItem -Path "HKCU:\Volatile Environment" -Name 64 | New-ItemProperty -Path $RegistryPath -Name "SessionID" -Value $CitrixSessionID -Force 65 | 66 | # Logon time 67 | $UserLogonTime = (Get-EventLog -LogName 'Application' -Source 'Citrix Desktop Service' -Newest 1 | Where EventID -EQ 1027).TimeWritten 68 | New-ItemProperty -Path $RegistryPath -Name "LogonTime" -Value $UserLogonTime -Force 69 | 70 | # Citrix Clientname 71 | $CitrixClientName = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Name 72 | New-ItemProperty -Path $RegistryPath -Name "Clientname" -Value $CitrixClientName -Force 73 | 74 | # Citrix Client 75 | $CitrixClientVer = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Version 76 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client Ver" -Value $CitrixClientVer -Force 77 | 78 | # Citrix Client IP 79 | $CitrixClientIP = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Address 80 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client IP" -Value $CitrixClientIP -Force 81 | 82 | # HDX Protocol 83 | $HDXProtocol = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Network_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Protocol 84 | New-ItemProperty -Path $RegistryPath -Name "HDX Protocol" -Value $HDXProtocol -Force 85 | 86 | # MTU 87 | $MTUSize = (ctxsession -v | findstr "EDT MTU:" | Select-Object -Last 1).split(":")[1].trimstart() 88 | New-ItemProperty -Path $RegistryPath -Name "MTU Size" -Value $MTUSize -Force 89 | 90 | # Rendezvous 91 | $Rendezvous = ((ctxsession -v | findstr "Rendezvous") | Select-Object -Last 1).split(":")[1].trimstart() 92 | New-ItemProperty -Path $RegistryPath -Name "Rendezvous" -Value $Rendezvous -Force 93 | 94 | # Proxy 95 | $Proxytransport = ((ctxsession -v | findstr "Transport") | Select-Object -Last 1).split(":")[1].trimstart() 96 | if ($Proxytransport -like "*PROXY*") { 97 | $Proxy = "YES" 98 | } 99 | else { 100 | $Proxy ="No" 101 | } 102 | New-ItemProperty -Path $RegistryPath -Name "Proxy" -Value $Proxy -Force 103 | 104 | 105 | 106 | # BGInfo # 107 | # Start BGInfo 108 | Start-Process -FilePath "$BGInfoDir\Bginfo64.exe" -ArgumentList @('/nolicprompt','/timer:0',"`"$BGInfoDir\$BGInfoFile`"") 109 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Replication/Replicate PVS vDisk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will replicate a PVS vDisk you choose from your PVS site. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to replicate vDisk versions to all other PVS servers in the site that hosts this vDisk 7 | 8 | .EXAMPLE 9 | & '.\Replicate PVS vDisk.ps1' or use shortcut. 10 | 11 | .NOTES 12 | If you want to change the root folder you have to modify the shortcut. 13 | 14 | .NOTES 15 | Version: 1.0 16 | Author: Dennis Mohrmann <@mohrpheus78> 17 | Creation Date: 2021-10-27 18 | Purpose/Change: 19 | 2021-10-27 Inital version 20 | #> 21 | 22 | 23 | 24 | # RunAs Admin 25 | function Use-RunAs 26 | { 27 | # Check if script is running as Administrator and if not elevate it 28 | # Use Check Switch to check if admin 29 | 30 | param([Switch]$Check) 31 | 32 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 33 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 34 | 35 | if ($Check) { return $IsAdmin } 36 | 37 | if ($MyInvocation.ScriptName -ne "") 38 | { 39 | if (-not $IsAdmin) 40 | { 41 | try 42 | { 43 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 44 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 45 | } 46 | catch 47 | { 48 | Write-Warning "Error - Failed to restart script elevated" 49 | break 50 | } 51 | exit 52 | } 53 | } 54 | } 55 | 56 | Use-RunAs 57 | 58 | 59 | # Variables 60 | $RootFolder = Split-Path -Path $PSScriptRoot 61 | $Date = Get-Date -UFormat "%d.%m.%Y" 62 | $Log = "$RootFolder\Replicate PVS vDisks.log" 63 | 64 | # Start logging 65 | Start-Transcript $Log | Out-Null 66 | 67 | $ScriptStart = Get-Date 68 | 69 | # Check if PVS SnapIn is available 70 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 71 | try { 72 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 73 | } 74 | catch { 75 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 76 | } 77 | 78 | # Replicate vDisks 79 | Write-Host -ForegroundColor Yellow "Replicate PVS vDisk" `n 80 | 81 | # Get PVS SiteName 82 | $SiteName = (Get-PvsSite).SiteName 83 | 84 | # Get all vDisks 85 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 86 | 87 | # Add property "ID" to object 88 | $ID = 1 89 | $AllvDisks | ForEach-Object { 90 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 91 | $ID += 1 92 | } 93 | 94 | # Show menu to select vDisk 95 | Write-Host "Available vDisks:" `n 96 | $ValidChoices = 1..($AllvDisks.Count) 97 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 98 | $Menu | Out-Host 99 | Write-Host 100 | $vDisk = Read-Host -Prompt 'Select vDisk to replicate' 101 | 102 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 103 | if ($vDisk.ID -notin $ValidChoices) { 104 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 105 | Read-Host "Press any key to exit" 106 | BREAK 107 | } 108 | 109 | # Get vDisk name and store 110 | $vDiskName = $vDisk.Name 111 | $StoreName = $vDisk.StoreName 112 | 113 | # Check if vDisk is already replicated 114 | $Replication = @(Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Select-Object -Property GoodInventoryStatus) 115 | if ($Replication -match "False") { 116 | 117 | # Export vDisk (XML file) 118 | Export-PvsDisk -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName -EA SilentlyContinue 119 | 120 | # Replicate vDisk to all PVS server in store 121 | $AllPVSServer = Get-PvsServer -StoreName $StoreName -SiteName $SiteName | Select-Object ServerName 122 | foreach ($PVSServer in $AllPVSServer | Where-Object {$_.ServerName -ne "$env:COMPUTERNAME"}) { 123 | $LocalStorePath = (Get-PvsStore -StoreName "$StoreName").Path 124 | $RemoteStorePath = $LocalStorePath -replace (":","$") 125 | $PVSServer = $PVSServer.ServerName 126 | robocopy.exe "$LocalStorePath" "\\$PVSServer\$RemoteStorePath" /COPYALL /XD WriteCache /XF *.lok /ETA /SEC 127 | } 128 | 129 | # Check Replication state 130 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $true} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Green ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 131 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $false} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Red ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 132 | 133 | Write-Host -ForegroundColor Green `n"Ready! vDisk $vDiskName replicated" `n 134 | } 135 | 136 | else { 137 | Write-Host -ForegroundColor Green "All vDisk versions replicated, no replication needed!" 138 | } 139 | 140 | $ScriptEnd = Get-Date 141 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 142 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 143 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" 144 | 145 | # Stop Logging 146 | Stop-Transcript | Out-Null 147 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 148 | Set-Content -Value $Content -Path $Log 149 | Rename-Item -Path $Log -NewName "Replicate PVS vDisks-$vDiskName-$Date.log" 150 | 151 | Read-Host `n "Press any key to exit" 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS/Create PVS VM.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will configure a hypervisor and the appropriate admin account to connect to the host and perform actions like start the PVS master VM 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to configure a hypervisor an admin account with a password and store this information in text files, the password is encrypted 7 | 8 | .NOTES 9 | 10 | Author: Dennis Mohrmann <@mohrpheus78> 11 | Creation Date: 2022-02-06 12 | #> 13 | 14 | # RunAs Admin 15 | function Use-RunAs 16 | { 17 | # Check if script is running as Administrator and if not elevate it 18 | # Use Check Switch to check if admin 19 | 20 | param([Switch]$Check) 21 | 22 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 23 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 24 | 25 | if ($Check) { return $IsAdmin } 26 | 27 | if ($MyInvocation.ScriptName -ne "") 28 | { 29 | if (-not $IsAdmin) 30 | { 31 | try 32 | { 33 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 34 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 35 | } 36 | catch 37 | { 38 | Write-Warning "Error - Failed to restart script elevated" 39 | break 40 | } 41 | exit 42 | } 43 | } 44 | } 45 | 46 | Use-RunAs 47 | 48 | # Variables 49 | $RootFolder = Split-Path -Path $PSScriptRoot 50 | $Date = Get-Date -UFormat "%d.%m.%Y" 51 | $Log = "$RootFolder\Logs\Create PVS VM.log" 52 | $HypervisorConfig = Import-Clixml "$RootFolder\Hypervisor\Hypervisor.xml" 53 | $Hypervisor = $HypervisorConfig.Hypervisor 54 | $PVSConfig = Import-Clixml "$RootFolder\PVS\PVS.xml" 55 | 56 | # Start logging 57 | Start-Transcript $Log | Out-Null 58 | 59 | # Citrix XenServer 60 | IF ($Hypervisor -eq "Xen") { 61 | # Check XenServer PS Module 62 | IF (!(Get-Module -ListAvailable -Name XenServerPSModule)) { 63 | Write-Host -ForegroundColor Red "No XenServer Powershell module found, aborting! Please copy module to 'C:\Program Files\WindowsPowerShell\Modules'" 64 | Read-Host "Press any key to exit" 65 | BREAK 66 | } 67 | 68 | # Connect to Xen host 69 | $Xen = $HypervisorConfig.Host 70 | $Credential = Import-CliXml -Path "$RootFolder\Hypervisor\Credentials-$ENV:Username-Xen.xml" 71 | Try { 72 | Connect-XenServer -url https://$Xen -Creds $Credential -NoWarnNewCertificates -SetDefaultSession | Out-Null 73 | } 74 | Catch { 75 | write-warning "Error: $_." 76 | } 77 | 78 | # Create VM's 79 | Write-Host -ForegroundColor Yellow "Creating virtual machines" 80 | $CSVpath = "$RootFolder\PVS\VDA.csv" 81 | $csv = Import-Csv $CSVpath -Delimiter ";" 82 | $csvHostnames = $CSV.Hostname 83 | 84 | foreach ($Hostnames in $CSV) { 85 | $Hostname = $Hostnames.Hostname 86 | $Mac = $Hostnames.Mac 87 | 88 | IF (!(Get-XenVM | Where-Object {$_.is_a_template -eq $False -and $_.is_a_snapshot -eq $False -and $_.domid -ne 0 -and $_.name_label -eq $Hostname})) { 89 | Invoke-XenVM -Name $PVSConfig.VDATemplate -XenAction Copy -NewName $Hostname -SR $PVSConfig.VMStorage 90 | Set-XenVM -Name $Hostname 91 | Invoke-XenVM -Name $Hostname -XenAction Provision 92 | (Get-XenVM -Name $Hostname).VIFs | Remove-XenVIF 93 | $VIF = Get-XenNetwork -Name $PVSConfig.VMNetwork 94 | $VM_ref=Get-XenVM -Name $Hostname | Select-Object -ExpandProperty opaque_ref 95 | New-XenVIF -VM $VM_ref -Network $VIF -MAC $Mac -Device 0 96 | $VM = Get-XenVM | Where-Object {$_.is_a_template -eq $False -and $_.is_a_snapshot -eq $False -and $_.domid -ne 0 -and $_.name_label -eq $Hostname} 97 | $VMName = $VM.name_label 98 | $VDI = $VM.VBDs | ForEach-Object { Get-XenVBD $_.opaque_ref | Where-Object {$_.type -notlike "CD"} } | ForEach-Object {Set-XenVDI -Ref $_.VDI -NameLabel ("$VMName" + "_D_Cache")} 99 | Write-Host -ForegroundColor Green "New virtual machines successfully created, check logfile '$log'"`n 100 | } 101 | ELSE { 102 | Write-Host -ForegroundColor Red "Virtual machine '$Hostname' already exists, skipping!"`n 103 | } 104 | } 105 | } 106 | 107 | # VMWare vSphere 108 | IF ($Hypervisor -eq "ESX") { 109 | # Check VMWare PS Module 110 | IF (!(Get-Module -ListAvailable -Name VMware.PowerCLI)) { 111 | Write-Host -ForegroundColor Red "No VMWare Powershell module found, aborting! Please install module to 'C:\Program Files\WindowsPowerShell\Modules'" 112 | Read-Host "Press any key to exit" 113 | BREAK 114 | } 115 | $ESX = $HypervisorConfig.Host 116 | $Credential = Import-CliXml -Path "$RootFolder\Hypervisor\Credentials-$ENV:Username-ESX.xml" 117 | Try { 118 | Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP $false -Confirm:$false | Out-Null 119 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -confirm:$false | Out-Null 120 | Connect-VIServer -server $ESX -Credential $Credential 121 | } 122 | Catch { 123 | write-warning "Error: $_." 124 | } 125 | 126 | # Create VM's 127 | Write-Host -ForegroundColor Yellow "Creating virtual machines" 128 | $CSVpath = "$RootFolder\PVS\VDA.csv" 129 | $csv = Import-Csv $CSVpath -Delimiter ";" 130 | $csvHostnames = $CSV.Hostname 131 | 132 | foreach ($hostnames in $CSV) { 133 | $Hostname = $Hostnames.Hostname 134 | $Mac = $Hostnames.Mac 135 | 136 | IF (!(Get-VM | Where-Object {$_.Name -eq $Hostname})) { 137 | New-VM -Name $Hostname -Template $PVSConfig.VDATemplate -Datastore $PVSConfig.VMStorage -VMHost $PVSConfig.Host 138 | Get-VM $Hostname | Get-NetworkAdapter | Where-Object {$_.NetworkName -eq $PVSConfig.VMNetwork } | Set-NetworkAdapter -MacAddress $Mac -Confirm:$false 139 | Write-Host -ForegroundColor Green "New virtual machines successfully created, check logfile '$log'"`n 140 | } 141 | ELSE { 142 | Write-Host -ForegroundColor Red "Virtual machine '$Hostname' already exists, skipping!"`n 143 | } 144 | } 145 | 146 | } 147 | 148 | # Stop Logging 149 | $ScriptEnd = Get-Date 150 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 151 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 152 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds"`n 153 | 154 | Stop-Transcript | Out-Null 155 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 156 | Set-Content -Value $Content -Path $Log 157 | Rename-Item -Path $Log -NewName "Create PVS VM-$Hypervisor-$Date.log" -EA SilentlyContinue 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/New PVS vDisk version.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will create a new PVS maintenance version from the vDisk you choose. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to create a new vDisk version from a list of available vDisk in your site. 7 | 8 | 9 | .EXAMPLE 10 | & '.\New PVS vDisk versionn.ps1' or use shortcut 11 | 12 | .NOTES 13 | If you want to change the root folder you have to modify the shortcut. 14 | 15 | Author: Dennis Mohrmann <@mohrpheus78> 16 | Creation Date: 2021-10-16 17 | #> 18 | 19 | 20 | # RunAs Admin 21 | function Use-RunAs 22 | { 23 | # Check if script is running as Administrator and if not elevate it 24 | # Use Check Switch to check if admin 25 | 26 | param([Switch]$Check) 27 | 28 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 29 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 30 | 31 | if ($Check) { return $IsAdmin } 32 | 33 | if ($MyInvocation.ScriptName -ne "") 34 | { 35 | if (-not $IsAdmin) 36 | { 37 | try 38 | { 39 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 40 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 41 | } 42 | catch 43 | { 44 | Write-Warning "Error - Failed to restart script elevated" 45 | break 46 | } 47 | exit 48 | } 49 | } 50 | } 51 | 52 | Use-RunAs 53 | 54 | 55 | # Variables 56 | $RootFolder = Split-Path -Path $PSScriptRoot 57 | $Date = Get-Date -UFormat "%d.%m.%Y" 58 | $Time = Get-Date -DisplayHint Time | foreach {$_ -replace ":", "-"} 59 | $NewvDiskLog = "$RootFolder\Logs\New PVS vDisk version-$Time.log" 60 | write-host $StartMaster 61 | 62 | # Start logging 63 | Start-Transcript $NewvDiskLog | Out-Null 64 | 65 | $ScriptStart = Get-Date 66 | 67 | # Check if PVS SnapIn is available 68 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 69 | try { 70 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 71 | } 72 | catch { 73 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 74 | } 75 | 76 | # New version 77 | Write-Host -ForegroundColor Yellow "New vDisk version" `n 78 | 79 | # Get PVS SiteName 80 | $SiteName = (Get-PvsSite).SiteName 81 | 82 | # Get all vDisks 83 | IF (-not(Test-Path variable:Task) -or $Task -eq $false) { 84 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 85 | 86 | # Add property "ID" to object 87 | $ID = 1 88 | $AllvDisks | ForEach-Object { 89 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 90 | $ID += 1 91 | } 92 | 93 | 94 | # Show menu to select vDisk 95 | Write-Host "Available vDisks:" `n 96 | $ValidChoices = 1..($AllvDisks.Count) 97 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 98 | $Menu | Out-Host 99 | Write-Host 100 | $vDisk = Read-Host -Prompt 'Select vDisk' 101 | 102 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 103 | if ($vDisk.ID -notin $ValidChoices) { 104 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 105 | Read-Host "Press any key to exit" 106 | BREAK 107 | } 108 | $vDiskName = $vDisk.Name 109 | $StoreName = $vDisk.StoreName 110 | } 111 | 112 | # Create new vDisk version if possible 113 | IF (-not(Test-Path variable:Task) -or $Task -eq $false) { 114 | $CanPromote = ((Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName) | Select-Object -First 1).CanPromote 115 | if ($CanPromote) { 116 | Write-Host -ForegroundColor Red "Current vDisk version is alreadey a in 'Maintenance' mode or in 'Test' mode!"`n 117 | 118 | $title = "" 119 | $message = "Do you want to use this version?" 120 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 121 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 122 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 123 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 124 | 125 | switch ($choice) { 126 | 0 { 127 | $answer1 = 'Yes' 128 | } 129 | 1 { 130 | $answer1 = 'No' 131 | } 132 | } 133 | 134 | if ($answer1 -eq 'Yes') { 135 | # Stop Logging 136 | $ScriptEnd = Get-Date 137 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 138 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 139 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds"`n 140 | 141 | Stop-Transcript | Out-Null 142 | $Content = Get-Content -Path $NewvDiskLog | Select-Object -Skip 18 143 | Set-Content -Value $Content -Path $NewvDiskLog 144 | Rename-Item -Path $NewvDiskLog -NewName "New PVS vDisk version-vDisk $vDiskName-Version $MaintVersion-$Date.log" -Force -EA SilentlyContinue 145 | } 146 | 147 | if ($answer1 -eq 'No') { 148 | Read-Host "Press any key to exit" 149 | BREAK 150 | } 151 | } 152 | else { 153 | # New maintenance version 154 | New-PvsDiskMaintenanceVersion -DiskLocatorName $vDiskName -StoreName $StoreName -SiteName $SiteName | Out-Null 155 | $MaintVersion = (Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName | Select-Object -First 1).Version 156 | Write-Host -ForegroundColor Green `n"New Version '$MaintVersion' successfully created, check logfile '$NewvDiskLog'"`n 157 | } 158 | } 159 | else { 160 | # New maintenance version if launched with task 161 | New-PvsDiskMaintenanceVersion -DiskLocatorName $vDiskName -StoreName $StoreName -SiteName $SiteName | Out-Null 162 | $MaintVersion = (Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName | Select-Object -First 1).Version 163 | Write-Host -ForegroundColor Green `n"New Version '$MaintVersion' successfully created, check logfile '$NewvDiskLog'"`n 164 | } 165 | 166 | 167 | # Start Master VM? Default Yes if doing Windows Updates 168 | IF ((Test-Path variable:Task) -or ($WindowsUpdates -eq $True) -or ($Task -eq $true)) { 169 | ."$PSScriptRoot\Start Master.ps1" 170 | } 171 | Else { 172 | $title = "" 173 | $message = "Do you want to start the master VM?" 174 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 175 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 176 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 177 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 178 | 179 | switch ($choice) { 180 | 0 { 181 | $answer2 = 'Yes' 182 | } 183 | 1 { 184 | $answer2 = 'No' 185 | } 186 | } 187 | 188 | if ($answer2 -eq 'Yes') { 189 | ."$PSScriptRoot\Start Master.ps1" 190 | } 191 | } 192 | 193 | IF (-not(Test-Path variable:Task) -or ($Task -eq $false)) { 194 | Read-Host "Press any key to exit" 195 | } 196 | 197 | # Stop Logging 198 | Stop-Transcript | Out-Null 199 | $Content = Get-Content -Path $NewvDiskLog | Select-Object -Skip 18 200 | Set-Content -Value $Content -Path $NewvDiskLog 201 | Rename-Item -Path $NewvDiskLog -NewName "New PVS vDisk version-$vDiskName-$Date.log" -Force -EA SilentlyContinue 202 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Promote PVS vDisk version.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will create a new PVS maintenance version from the vDisk you choose. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to create a new vDisk version from a list of available vDisk in your site. 7 | 8 | 9 | .EXAMPLE 10 | & '.\New PVS vDisk versionn.ps1' or use shortcut 11 | 12 | .NOTES 13 | If you want to change the root folder you have to modify the shortcut. 14 | 15 | Author: Dennis Mohrmann <@mohrpheus78> 16 | Creation Date: 2021-10-16 17 | #> 18 | 19 | 20 | # RunAs Admin 21 | function Use-RunAs 22 | { 23 | # Check if script is running as Administrator and if not elevate it 24 | # Use Check Switch to check if admin 25 | 26 | param([Switch]$Check) 27 | 28 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 29 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 30 | 31 | if ($Check) { return $IsAdmin } 32 | 33 | if ($MyInvocation.ScriptName -ne "") 34 | { 35 | if (-not $IsAdmin) 36 | { 37 | try 38 | { 39 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 40 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 41 | } 42 | catch 43 | { 44 | Write-Warning "Error - Failed to restart script elevated" 45 | break 46 | } 47 | exit 48 | } 49 | } 50 | } 51 | 52 | Use-RunAs 53 | 54 | 55 | # Variables 56 | $RootFolder = Split-Path -Path $PSScriptRoot 57 | $Date = Get-Date -UFormat "%d.%m.%Y" 58 | $PromotevDiskLog = "$RootFolder\Logs\Promote PVS vDisk version.log" 59 | 60 | # Start logging 61 | Start-Transcript $PromotevDiskLog | Out-Null 62 | 63 | $ScriptStart = Get-Date 64 | 65 | # Check if PVS SnapIn is available 66 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 67 | try { 68 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 69 | } 70 | catch { 71 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 72 | } 73 | 74 | # Merge vDisks 75 | Write-Host -ForegroundColor Yellow "Promote vDisk version" `n 76 | 77 | # Get PVS SiteName 78 | $SiteName = (Get-PvsSite).SiteName 79 | 80 | # Get all vDisks 81 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 82 | 83 | # Add property "ID" to object 84 | $ID = 1 85 | $AllvDisks | ForEach-Object { 86 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 87 | $ID += 1 88 | } 89 | 90 | # Show menu to select vDisk 91 | Write-Host "Available vDisks:" `n 92 | $ValidChoices = 1..($AllvDisks.Count) 93 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 94 | $Menu | Out-Host 95 | Write-Host 96 | $vDisk = Read-Host -Prompt 'Select vDisk' 97 | 98 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 99 | if ($vDisk.ID -notin $ValidChoices) { 100 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 101 | Read-Host "Press any key to exit" 102 | BREAK 103 | } 104 | 105 | $vDiskName = $vDisk.Name 106 | $StoreName = $vDisk.StoreName 107 | 108 | # vDisk in maintenance mode? 109 | $CanPromote = ((Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName) | Select-Object -First 1).CanPromote 110 | if (-not($CanPromote)) { 111 | Write-Host -ForegroundColor Red "Selected vDisk version is not in maintenance mode, aborting!" 112 | Read-Host "Press any key to exit" 113 | BREAK 114 | } 115 | 116 | # Get maintenance version 117 | $MaintVersion = (Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.CanPromote -eq 'True'}).Version 118 | Write-Host `n 119 | 120 | # Production or test mode? 121 | $title = "" 122 | $message = "Do you want to promote to production or test mode?" 123 | $Prod = New-Object System.Management.Automation.Host.ChoiceDescription "&P" 124 | $Test = New-Object System.Management.Automation.Host.ChoiceDescription "&T" 125 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($Prod, $Test) 126 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 127 | 128 | switch ($choice) { 129 | 0 { 130 | $answer = 'P' 131 | } 132 | 1 { 133 | $answer = 'T' 134 | } 135 | } 136 | if ($answer -eq 'P') { 137 | Invoke-PvsPromoteDiskVersion -DiskLocatorName $vDiskName -StoreName $StoreName -SiteName $SiteName 138 | } 139 | else { 140 | Invoke-PvsPromoteDiskVersion -DiskLocatorName $vDiskName -StoreName $StoreName -SiteName $SiteName -Test 141 | } 142 | 143 | # Description 144 | Write-Host -ForegroundColor Yellow `n"Please enter a description for the new vDisk version and hit enter"`n 145 | $Description = Read-Host 146 | Set-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName -Version $MaintVersion -Description "$Description" 147 | 148 | Write-Host -ForegroundColor Green `n"vDisk successfully promoted to version '$MaintVersion' with description '$Description', check logfile"`n 149 | 150 | # Replicate vDisk to all PVS server in store 151 | $title = "" 152 | $message = "Do you want to replicate the new vDisk version?" 153 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 154 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 155 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 156 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 157 | 158 | switch ($choice) { 159 | 0 { 160 | $answer = 'Yes' 161 | } 162 | 1 { 163 | $answer = 'No' 164 | } 165 | } 166 | 167 | if ($answer -eq 'Yes') { 168 | $AllPVSServer = Get-PvsServer -StoreName $StoreName -SiteName $SiteName | Select-Object ServerName 169 | foreach ($PVSServer in $AllPVSServer | Where-Object {$_.ServerName -ne "$env:COMPUTERNAME"}) { 170 | $LocalStorePath = (Get-PvsStore -StoreName "$StoreName").Path 171 | $RemoteStorePath = $LocalStorePath -replace (":","$") 172 | $PVSServer = $PVSServer.ServerName 173 | robocopy.exe "$LocalStorePath" "\\$PVSServer\$RemoteStorePath" /COPYALL /XD WriteCache /XF *.lok /ETA /SEC 174 | } 175 | 176 | # Check Replication state 177 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $true} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Green ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 178 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $false} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Red ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 179 | } 180 | 181 | # Stop Logging 182 | $ScriptEnd = Get-Date 183 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 184 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 185 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" 186 | 187 | Stop-Transcript | Out-Null 188 | $Content = Get-Content -Path $PromotevDiskLog | Select-Object -Skip 18 189 | Set-Content -Value $Content -Path $PromotevDiskLog 190 | Rename-Item -Path $PromotevDiskLog -NewName "Promote PVS vDisk version-$vDiskName-$Date.log" -Force -EA SilentlyContinue 191 | 192 | Read-Host "Press any key to exit" -------------------------------------------------------------------------------- /Teams Optimization check/Check Teams optimization.ps1: -------------------------------------------------------------------------------- 1 | # **************************************************** 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # Check MS Teams optimization state and notify user 4 | # **************************************************** 5 | 6 | <# 7 | .SYNOPSIS 8 | This script will check if the MS Teams Citrix Optimization is working after starting Teams. After 30 sec. (launch time of Teams) the user gets a toast notificaton if the optimization is NOT active. 9 | A log for each client gets written to the "Logging" folder (which must exist with write permissions for users!) 10 | You need to create a shortcut for the user to launch the script. Replace the shortcut with the standard Teams shortcut. 11 | 12 | .DESCRIPTION 13 | The script will first find the current session ID and the clientname of the user and what client platform/version is used in this session. The display language is determined to display 14 | the notification in the correct language. The toast notification appears longer than the default value (line 138). 15 | 16 | .EXAMPLE 17 | WEM action 18 | Command line: 19 | powershell.exe 20 | 21 | Working directory: 22 | C:\Program Files (x86)\Microsoft\Teams\current 23 | 24 | Parameters: 25 | -executionpolicy bypass -windowstyle hidden -file "C:\Program Files (x86)\Scripts\Check Teams optimization.ps1" 26 | 27 | .NOTES 28 | Attention: 29 | 30 | Requires a registry key on the VDA! 31 | HKLM\Software\Citrix\HDXMediaStream 32 | Name: WebrtcDirectorIntegration 33 | Type: DWORD 34 | Value: 1 35 | 36 | Requires a shortcut for the users to launch Teams (see information above) 37 | 38 | Requires the BurntToast Powershell Module! https://github.com/Windos/BurntToast 39 | Use "Install-Module -Name BurntToast" to install the module. 40 | BurntToast needs an AppId to display the notifications, default is Windows Powershell. BurntToast will check the start menu for the shortcut, no message is shown if Powershell cannot be found. 41 | In many cases admins hide the Powershell shortcuts from the start menu, so you have to define your own AppId. 42 | To define you own AppId you have to place a shortcut in the start menu and use this as your AppId. The name of the AppId will be displayed at the bottom of the notification. 43 | To find out how to define the AppID, run "Get-StartApps". You get a list of possible values. 44 | In this case I use MS Teams as AppID, a shortcut to this powershell script must exist in the start menu! 45 | You get more information about the AppID here https://docs.microsoft.com/en-us/windows/win32/shell/appids and here https://toastit.dev/2018/02/04/burnttoast-appid-installer/. 46 | 47 | Place the script in a local folder on the VDA, together with the Teams.png file. Create a folder "Logging" with write permissions for the users. 48 | 49 | 50 | Version: 1.1 51 | Author: Dennis Mohrmann <@mohrpheus78> 52 | Creation Date: 2021-02-19 53 | Purpose/Change: 54 | 2021-03-01 Inital version 55 | 2021-03-02 Added notes 56 | 2021-03-04 Added notes 57 | 2021-03-16 Changed notes 58 | 2021-03-22 Upload to GitHub 59 | #> 60 | 61 | #==================================================================================== 62 | Function WriteLog { 63 | 64 | [CmdletBinding()] 65 | 66 | Param( 67 | [Parameter( 68 | Mandatory=$true, Position = 1)] 69 | [AllowEmptyString()][String]$Text, 70 | [Parameter( 71 | Mandatory=$true, Position = 2)] 72 | [AllowEmptyString()][String]$LogFile 73 | ) 74 | 75 | begin {} 76 | 77 | process { 78 | if ( $Text -eq "" ) { 79 | Add-Content $LogFile -value ("") # Write an empty line 80 | } Else { 81 | Add-Content $LogFile -value ($Text) 82 | } 83 | } 84 | 85 | end {} 86 | } 87 | #==================================================================================== 88 | 89 | # Lanch MS Teams and wait 25 seconds to check the status 90 | Start-Process -FilePath "${env:ProgramFiles(x86)}\Microsoft\Teams\current\Teams.exe" 91 | Start-Sleep -s 30 92 | 93 | # General variables 94 | $DateTime = (Get-Date -format dd-MM-yyyy) + " " + (Get-Date -format HH:mm:ss) 95 | $Language = [CultureInfo]::InstalledUICulture.Name 96 | $CitrixSessionID = Get-ChildItem -Path "HKCU:\Volatile Environment" -Name 97 | $CitrixClientName = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Name 98 | [version]$CitrixClientVersion = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Version 99 | [version]$WindowsClientMin = "19.7.0.15" 100 | [version]$MacClientMin = "20.12.0.3" 101 | [version]$LinuxClientMin = "20.06.0.15" 102 | $TeamsOptimization = (Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Webrtc_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID}) | Select-Object -ExpandProperty Component_VersionTypescript 103 | $TeamsVersion = (Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -like "*Teams Machine*"}).DisplayVersion 104 | $AppId = (Get-StartApps | Where-Object {$_.Name -like "*Teams*"}).AppId 105 | 106 | # Citrix Client platform 107 | $ClientProductId=(Get-ItemProperty HKLM:\Software\Citrix\ICA\Session\$CitrixSessionID\Connection -name ClientProductId).ClientproductId 108 | if ($ClientProductId -eq 1) {$ClientPlatform="Windows"} 109 | if ($ClientProductId -eq 81) {$ClientPlatform="Linux"} 110 | if ($ClientProductId -eq 82) {$ClientPlatform="Mac"} 111 | if ($ClientProductId -eq 257) {$ClientPlatform="HTML5"} 112 | 113 | # BurntToast variables 114 | $BTAppIcon = New-BTImage -Source "$PSScriptRoot\Teams.png" -AppLogoOverride 115 | $BTAppId = $AppId # MS Teams shortcut for this script 116 | $BTAudio = New-BTAudio -Source ms-winsoundevent:Notification.IM 117 | if ($Language -eq "de-DE") { 118 | $BTText1 = New-BTText -Text "MS Teams ist NICHT optimiert!" 119 | $BTText2 = New-BTText -Text "Citrix Client Version $CitrixClientVersion ($ClientPlatform)." 120 | $BTText3 = New-BTText -Text "Bitte IT Helpdesk kontaktieren" 121 | } 122 | else { 123 | $BTText1 = New-BTText -Text "MS Teams is NOT optimized!" 124 | $BTText2 = New-BTText -Text "Citrix client version $CitrixClientVersion ($ClientPlatform)." 125 | $BTText3 = New-BTText -Text "Please contact IT Helpdesk" 126 | } 127 | 128 | # Client platform 129 | switch ($ClientPlatform) 130 | { 131 | 'Windows' { 132 | if ($CitrixClientVersion -lt $WindowsClientMin) { 133 | $BTText3 = New-BTText -Text "Your Citrix client is not supported"} 134 | } 135 | 136 | 'Mac' { 137 | if ($CitrixClientVersion -lt $MacClientMin) { 138 | $BTText3 = New-BTText -Text "Your Citrix client is not supported"} 139 | } 140 | 141 | 'Linux' { 142 | if ($CitrixClientVersion -lt $LinuxClientMin) { 143 | $BTText3 = New-BTText -Text "Your Citrix client is not supported"} 144 | } 145 | } 146 | 147 | $BTBinding = New-BTBinding -Children $BTText1, $BTText2, $BTText3 -AppLogoOverride $BTAppIcon 148 | $BTVisual = New-BTVisual -BindingGeneric $BTBinding 149 | $BTContent = New-BTContent -Visual $BTVisual -Audio $BTAudio -Duration Long 150 | New-BTAppId -AppId $BTAppId 151 | 152 | # Logging 153 | $LogFile = "$PSScriptRoot\Logging\$CitrixClientName-MS Teams Optimization.log" 154 | New-Item $LogFile -ItemType "file" -force | Out-Null 155 | WriteLog "START SCRIPT" $LogFile 156 | WriteLog "$DateTime" $LogFile 157 | WriteLog "Clientname: $CitrixClientName" $LogFile 158 | WriteLog "Platform: $ClientPlatform" $LogFile 159 | WriteLog "Current client version: $CitrixClientVersion" $LogFile 160 | 161 | # BurntToast Notification if NOT optimized! 162 | if ($TeamsOptimization -eq "0.0.0.0") { 163 | Submit-BTNotification -Content $BTContent -AppId $BTAppId 164 | WriteLog "Teams NOT optimized " $LogFile 165 | } 166 | else { 167 | WriteLog "Teams optimized " $LogFile 168 | } 169 | 170 | 171 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Merge/Merge PVS vDisk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will merge a PVS vDisk you choose. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to merge vDisk versions to a merged base and promote the new base to production. After that the vDisk will be replicated to all other PVS servers in 7 | the site that hosts this vDisk if you want. You can also generate a HTML report of your vDisk versions. In this case you also have to place the "vDisk Documentation" folder in the scripts folder. 8 | 9 | .EXAMPLE 10 | & '.\Merge PVS vDisk.ps1' or use shortcut 11 | 12 | .NOTES 13 | If you want to change the root folder you have to modify the shortcut. 14 | 15 | Version: 1.0 16 | Author: Dennis Mohrmann <@mohrpheus78> 17 | Creation Date: 2021-10-16 18 | Purpose/Change: 19 | 2021-10-16 Inital version 20 | 2021-10-26 changes to menu 21 | 2021-10-27 changed description 22 | #> 23 | 24 | 25 | # RunAs Admin 26 | function Use-RunAs 27 | { 28 | # Check if script is running as Administrator and if not elevate it 29 | # Use Check Switch to check if admin 30 | 31 | param([Switch]$Check) 32 | 33 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 34 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 35 | 36 | if ($Check) { return $IsAdmin } 37 | 38 | if ($MyInvocation.ScriptName -ne "") 39 | { 40 | if (-not $IsAdmin) 41 | { 42 | try 43 | { 44 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 45 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 46 | } 47 | catch 48 | { 49 | Write-Warning "Error - Failed to restart script elevated" 50 | break 51 | } 52 | exit 53 | } 54 | } 55 | } 56 | 57 | Use-RunAs 58 | 59 | 60 | # Variables 61 | $RootFolder = Split-Path -Path $PSScriptRoot 62 | $Date = Get-Date -UFormat "%d.%m.%Y" 63 | $Log = "$RootFolder\Logs\Merge PVS vDisks.log" 64 | 65 | # Start logging 66 | Start-Transcript $Log | Out-Null 67 | 68 | $ScriptStart = Get-Date 69 | 70 | # Check if PVS SnapIn is available 71 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 72 | try { 73 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 74 | } 75 | catch { 76 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 77 | } 78 | 79 | # Merge vDisks 80 | Write-Host -ForegroundColor Yellow "Merge PVS vDisk" `n 81 | 82 | # Get PVS SiteName 83 | $SiteName = (Get-PvsSite).SiteName 84 | 85 | # Get all vDisks 86 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 87 | 88 | # Add property "ID" to object 89 | $ID = 1 90 | $AllvDisks | ForEach-Object { 91 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 92 | $ID += 1 93 | } 94 | 95 | # Show menu to select vDisk 96 | Write-Host "Available vDisks:" `n 97 | $ValidChoices = 1..($AllvDisks.Count) 98 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 99 | $Menu | Out-Host 100 | Write-Host 101 | $vDisk = Read-Host -Prompt 'Select vDisk to merge' 102 | 103 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 104 | if ($vDisk.ID -notin $ValidChoices) { 105 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 106 | Read-Host "Press any key to exit" 107 | BREAK 108 | } 109 | 110 | $vDiskName = $vDisk.Name 111 | $StoreName = $vDisk.StoreName 112 | 113 | # Merge selected vDisk if possible 114 | $CanMerge = ((Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName) | Select-Object -First 1 | Where-Object {$_.CanMerge -eq 'False'}) 115 | if (-not($CanMerge)) { 116 | Write-Host -ForegroundColor Red "Current vDisk version is a merged base or in private mode, aborting!" 117 | Read-Host "Press any key to exit" 118 | BREAK 119 | } 120 | 121 | else { 122 | Merge-PvsDisk -DiskLocatorName "$vDiskName" -StoreName "$StoreName" -SiteName "$SiteName" -NewBase 123 | } 124 | 125 | # Wait until merging is finished 126 | Do { 127 | Write-Host -ForegroundColor Green "Merging, please wait..." 128 | $MergeTask = (Get-PvsTask | Select-Object -Last 1).State 129 | Start-Sleep 8 130 | } 131 | Until ($MergeTask -eq 2) 132 | 133 | # Promote vDisk to production 134 | Invoke-PvsPromoteDiskVersion -DiskLocatorName "$vDiskName" -StoreName "$StoreName" -SiteName "$SiteName" 135 | 136 | # Get version number of base 137 | $LastVersion = (Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName).Version | Select-Object -First 1 138 | 139 | # Enter description "Merged Base" into merged base disk 140 | Set-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName -Version $LastVersion -Description "Merged Base" 141 | 142 | # Export vDisk (XML file) 143 | Export-PvsDisk -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName -EA SilentlyContinue 144 | 145 | # Replicate vDisk to all PVS server in store 146 | $title = "Replicate vDisks" 147 | $message = "Do you want to replicate the merged base disk?" 148 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 149 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 150 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 151 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 152 | 153 | switch ($choice) { 154 | 0 { 155 | $answer = 'Yes' 156 | } 157 | 1 { 158 | $answer = 'No' 159 | } 160 | } 161 | 162 | if ($answer -eq 'Yes') { 163 | $AllPVSServer = Get-PvsServer -StoreName $StoreName -SiteName $SiteName | Select-Object ServerName 164 | foreach ($PVSServer in $AllPVSServer | Where-Object {$_.ServerName -ne "$env:COMPUTERNAME"}) { 165 | $LocalStorePath = (Get-PvsStore -StoreName "$StoreName").Path 166 | $RemoteStorePath = $LocalStorePath -replace (":","$") 167 | $PVSServer = $PVSServer.ServerName 168 | robocopy.exe "$LocalStorePath" "\\$PVSServer\$RemoteStorePath" /COPYALL /XD WriteCache /XF *.lok /ETA /SEC 169 | } 170 | 171 | # Check Replication state 172 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $true} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Green ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 173 | Get-PvsDiskVersion -Name $vDiskName -SiteName $SiteName -StoreName $StoreName | Where-Object {$_.GoodInventoryStatus -eq $false} | Sort-Object -Property Version | ForEach-Object {write-host -foregroundcolor Red ("Version: " + $_.Version + " Replication state: " + $_.GoodInventoryStatus)} 174 | } 175 | 176 | # Create HTML Report 177 | $title = "Create Report" 178 | $message = "Do you want to create a HTML report?" 179 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 180 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 181 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 182 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 183 | 184 | switch ($choice) 185 | { 186 | 0 { 187 | $answer = 'Yes' 188 | } 189 | 1 { 190 | $answer = 'No' 191 | } 192 | } 193 | 194 | if ($answer -eq 'Yes') 195 | { 196 | & "$RootFolder\vDisk Documentation\PVS vDisk versions.ps1" -outputpath "$ENV:USERPROFILE\Desktop" 197 | } 198 | 199 | Write-Host -ForegroundColor Green "Ready! Merged base version is version $LastVersion" `n 200 | 201 | $ScriptEnd = Get-Date 202 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 203 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 204 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" 205 | 206 | # Stop Logging 207 | Stop-Transcript | Out-Null 208 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 209 | Set-Content -Value $Content -Path $Log 210 | Rename-Item -Path $Log -NewName "Merge PVS vDisks-$vDiskName-$Date.log" -EA SilentlyContinue 211 | 212 | Read-Host "Press any key to exit" -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Evergreen.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will automatically install all avaialable software updates on a device with the help of the Evergreen scripot from Manuel Winkkel (@deyda). The server will automatically reboot if needed, after reboot 4 | BIS-F will be launched to seal the image if you want. At the end the new vDisk will be promoted to test. 5 | 6 | .DESCRIPTION 7 | The purpose of the script is to remotely install software updates with the Evergreen script. 8 | IMPORTANT: You have to create a list with the software components you want to install. Launch Evergreen, make a selection and save. Rename the saved file as "NAME_OF_MASTER-Install.txt" 9 | 10 | .NOTES 11 | Author: Dennis Mohrmann <@mohrpheus78> 12 | Creation Date: 2022-02-17 13 | #> 14 | 15 | # Variables 16 | $Date = Get-Date -UFormat "%d.%m.%Y" 17 | $RootFolder = Split-Path -Path $PSScriptRoot 18 | $HypervisorConfig = Import-Clixml "$RootFolder\Hypervisor\Hypervisor.xml" 19 | $Hypervisor = $HypervisorConfig.Hypervisor 20 | $PVSConfig = Import-Clixml "$RootFolder\PVS\PVS.xml" 21 | $BISF = $PVSConfig.BISF 22 | $EvergreenConfig = Import-Clixml "$RootFolder\Evergreen\Evergreen.xml" 23 | $EvergreenShare = $EvergreenConfig.EvergreenShare 24 | 25 | # Check free space on drive C: 26 | $FreeSize = Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 27 | (Get-Volume -DriveLetter C) | ForEach-Object {[math]::Round($_.SizeRemaining / 1GB, 1)} 28 | } 29 | IF ([int]$FreeSize -lt 5) { 30 | Write-Host `n 31 | Write-Host -ForegroundColor Red "Attention, not enough free space on drive C: to perform the updates, please free up space, free space is $FreeSize GB!"`n 32 | Write-Host "$MaintDeviceName ist still running, please shut down the server! Press Enter to exit" 33 | Read-Host 34 | BREAK 35 | } 36 | 37 | ELSE { 38 | Write-Host -ForegroundColor Green "Enough free space ($FreeSize GB) on drive C: to perform the updates, please wait..."`n 39 | Do { 40 | #Reset Timeouts 41 | $ConnectionTimeout = 0 42 | $Evergreen = 0 43 | 44 | #Starts up a remote powershell session to the computer 45 | Do { 46 | $session = New-PSSession -ComputerName $MaintDeviceName 47 | Write-Host "Reconnecting to $MaintDeviceName" `n 48 | Start-Sleep -seconds 10 49 | $connectiontimeout++ 50 | } Until ($session.state -match "Opened" -or $connectiontimeout -ge 10) 51 | 52 | # Create a new task for Evergreen 53 | Write-Host -ForegroundColor Yellow "Create scheduled task for launching Evergreen" 54 | Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 55 | Get-ScheduledTask -TaskName "Evergreen" -EA SilentlyContinue | Unregister-ScheduledTask -Confirm:$false 56 | } 57 | Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 58 | $Installer = "$Using:EvergreenShare\Evergreen-Software Installer.ps1" 59 | $Options = @( 60 | "-file" 61 | "`"$Installer`"" 62 | "-noGUI" 63 | "-SoftwareToAutoInstall" 64 | ) 65 | $Action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "$Options" 66 | $User = "NT AUTHORITY\SYSTEM" 67 | Register-ScheduledTask -TaskName "Evergreen" -User $User -Action $Action -RunLevel Highest –Force | Out-Null 68 | } 69 | 70 | # Run Evergreen task 71 | Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock {Start-ScheduledTask -TaskName "Evergreen" | Out-Null} 72 | Start-Sleep -seconds 3 73 | Write-Host "Evergreen is running..."`n 74 | Do { 75 | $EvergreenLog = (Get-ChildItem -Path "$EvergreenShare\Software\_Install Logs" | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name 76 | #$EvergreenStatus = Get-Content "$EvergreenShare\_Install Logs\$EvergreenLog" 77 | Get-Content "$EvergreenShare\Software\_Install Logs\$EvergreenLog" | Select-Object -Last 1 | Select-String -Pattern Installing -ErrorAction SilentlyContinue 78 | Start-Sleep -Seconds 5 79 | $Finished = Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 80 | (Get-ScheduledTask -TaskName 'Evergreen').State 81 | } 82 | } Until ($Finished.Value -eq "Ready") 83 | Write-Host -ForegroundColor Green "Finished..."`n 84 | $EvergreenLog = (Get-ChildItem -Path "$EvergreenShare\Software\_Install Logs" | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name 85 | $Updates = Get-Content -Path "$EvergreenShare\Software\_Install Logs\$EvergreenLog" | Select-String -Pattern Installing 86 | $Updates = ($Updates -replace ("Uninstalling","") -replace ("Installing","") | Select-Object -Unique) -join "," 87 | Write-Host "Updates installed: $Updates"`n 88 | $Evergreen = 1 89 | Write-Host -ForegroundColor Yellow "Restarting '$MaintDeviceName'"`n 90 | Start-Sleep -Seconds 6 91 | Restart-Computer -Wait -ComputerName $MaintDeviceName -Force 92 | 93 | } Until ($Evergreen -eq 1) 94 | } 95 | 96 | # Sealing VM with BIS-F 97 | IF ($BISF -eq "YES") { 98 | # Get PVS cache drive letter 99 | $CacheDrive = Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 100 | (Get-WmiObject -Class Win32_logicaldisk -Filter "DriveType = '3'" | Where-Object {$_.DeviceID -ne "C:"}).DeviceID 101 | } 102 | $CacheDrive = $CacheDrive -replace (":","$") 103 | $BISFLogLocation = Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock { 104 | (Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Login Consultants\BISF" -Name LIC_BISF_CLI_LS -ErrorAction SilentlyContinue).LIC_BISF_CLI_LS 105 | } 106 | 107 | Write-Host -ForegroundColor Yellow "Starting BIS-F to seal the image"`n 108 | $BISFTask = Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock {Get-ScheduledTask -TaskName "BIS-F" -ErrorAction SilentlyContinue} 109 | IF ($BISFTask -eq $Null) { 110 | copy-item "C:\Program Files (x86)\PVS Admin Toolkit\vDisk Maintenance\BIS-F.xml" "\\$MaintDeviceName\admin$\Temp" 111 | invoke-Command -ComputerName $MaintDeviceName -ScriptBlock {Register-ScheduledTask -Xml (Get-Content "C:\Windows\Temp\BIS-F.xml" | out-string) -TaskName "BIS-F"} 112 | } 113 | Invoke-Command -ComputerName $MaintDeviceName -ScriptBlock {Start-ScheduledTask -TaskName "BIS-F" | Out-Null} 114 | Start-Sleep -seconds 30 115 | Write-Host "BIS-F is running..."`n 116 | 117 | IF ([string]::ISNullOrEmpty( $BISFLogLocation) -eq $True) { 118 | Do { 119 | $BISFLog = ((Get-ChildItem -Path "\\$MaintDeviceName\$CacheDrive\BISFLogs") | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name 120 | $BISFStatus = Get-Content "\\$MaintDeviceName\$CacheDrive\BISFLogs\$BISFLog" 121 | Get-Content "\\$MaintDeviceName\$CacheDrive\BISFLogs\$BISFLog" | select-object -Last 1 122 | Start-Sleep -Seconds 1 123 | $Finished = ([regex]::Matches($BISFStatus, "End Of Script" )) 124 | } Until ($Finished.Value -eq "End of Script") 125 | } 126 | ELSE { 127 | Do { 128 | $BISFLog = ((Get-ChildItem -Path "$BISFLogLocation\$MaintDeviceName") | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name 129 | $BISFStatus = Get-Content "$BISFLogLocation\$MaintDeviceName\$BISFLog" 130 | Get-Content "$BISFLogLocation\$MaintDeviceName\$BISFLog" | Select-Object -Last 1 131 | Start-Sleep -Seconds 1 132 | $Finished = ([regex]::Matches($BISFStatus, "End Of Script" )) 133 | } Until ($Finished.Value -eq "End of Script") 134 | } 135 | } 136 | 137 | #Shutdown VM without using BIS-F 138 | ELSE { 139 | invoke-Command -ComputerName $MaintDeviceName -ScriptBlock {shutdown -s -t 1 -f} 140 | } 141 | 142 | # Wait for shutdown 143 | # Citrix XenServer 144 | IF ($Hypervisor -eq "Xen") { 145 | Do { 146 | Write-Host -ForegroundColor Yellow "VM '$MaintDeviceName' is shutting down..."`n 147 | $Powerstate = (Get-XenVM | Where-Object {$_.name_label -eq "$MaintDeviceName"}) 148 | Start-Sleep -seconds 10 149 | } Until ($Powerstate.power_state -eq "Halted") 150 | } 151 | 152 | # VMWare vSphere 153 | IF ($Hypervisor -eq "ESX") { 154 | Do { 155 | Write-Host -ForegroundColor Yellow "VM '$MaintDeviceName' is shutting down..."`n 156 | $Powerstate = (Get-VM | Where-Object {$_.Name -eq "$MaintDeviceName"}) 157 | Start-Sleep -seconds 10 158 | } Until ($Powerstate.PowerState -eq "PoweredOff") 159 | } 160 | 161 | # Nutanix AHV 162 | IF ($Hypervisor -eq "AHV") { 163 | Do { 164 | Write-Host -ForegroundColor Yellow "VM '$MaintDeviceName' is shutting down..."`n 165 | $Powerstate = (Get-NTNXVirtualMachine | Where-Object {$_.Name -eq "$MaintDeviceName"}) 166 | Start-Sleep -seconds 10 167 | } Until ($Powerstate.PowerState -eq "OFF") 168 | } 169 | Write-Host -ForegroundColor Green "'$MaintDeviceName' shutdown" `n 170 | 171 | #Promote vDisk to Test 172 | Write-Host -ForegroundColor Yellow "Promoting vDisk '$vDiskName' version $MaintVersion to test mode" `n 173 | Invoke-PvsPromoteDiskVersion -DiskLocatorName $vDiskName -StoreName $StoreName -SiteName $SiteName -Test 174 | Set-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName -Version $MaintVersion -Description "Update $Updates" 175 | Write-Host -ForegroundColor Green "Ready, start device in test mode to check vDisk!" 176 | 177 | # Replicate vDisk 178 | Write-Host -ForegroundColor Yellow "Executing vDisk replication script" `n 179 | ."$Rootfolder\vDisk Replication\Replicate PVS vDisk.ps1" 180 | 181 | -------------------------------------------------------------------------------- /Citrix Client notification/Citrix Client notification.ps1: -------------------------------------------------------------------------------- 1 | # ***************************************************** 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # Check Citrix Client version and notify user to update 4 | # ***************************************************** 5 | 6 | <# 7 | .SYNOPSIS 8 | This script will check which Citrix client is installed on the endpoint (Platform and version). You define a minimum version, if the clients endpoint version is lower, the user gets 9 | a toast notificaton that the client is out of date (or whatever you want). You can also inform the user that a HTML5 client is in use and that this client isn't supported. 10 | A log for each client gets written to the "Logging" folder (which must exist!) 11 | 12 | .DESCRIPTION 13 | The script will first find the current session id and the cientname of the user and what client platform/version is used in this session. The display language is determined to display 14 | the notification in the correct language. The toast notification appears longer than the default value (line 112). 15 | 16 | .PARAMETER -WindowsClientMin 17 | You can override the predifined versions 18 | - WindowsClientMin "20.12.0.39" 19 | .PARAMETER -MacClientMin 20 | You can override the predifined versions 21 | -MacClientMin "20.12.0.3" 22 | .PARAMETER -LinuxClientMin 23 | You can override the predifined versions 24 | -LinuxClientMin "21.1.0.14" 25 | .PARAMETER -MailButton 26 | This one is mandatory, if you want to give the user the possibility to generate a mail for the support submit "True", otherwise "False" 27 | -MailButton True 28 | 29 | .EXAMPLE 30 | Powershell logonscript: 31 | Script Name: 32 | C:\Program Files (x86)\SuL\Scripts\Notifications\Citrix Client notification.ps1 33 | Script parameters: 34 | -WindowsClientMin "20.12.1.42" -MacClientMin "20.12.0.3" 35 | 36 | WEM external task: 37 | Path: powershell.exe 38 | Arguments: 39 | -executionpolicy bypass -file "C:\Program Files (x86)\Scripts\Citrix Client notification.ps1" 40 | 41 | .NOTES 42 | Attention: Requires the BurntToast Powershell Module! https://github.com/Windos/BurntToast 43 | Use "Install-Module -Name BurntToast" to install the module. 44 | BurntToast needs an AppId to display the notifications, default is Windows Powershell. BurntToast will check the start menu for the shortcut, no message is shown if Powershell cannot be found. 45 | In many cases admins hide the Powershell shortcuts from the start menu, so you have to define your own AppId. 46 | To define you own AppId you have to place a shortcut in the start menu and use this as your AppId. (e.g. a png file). The name of the AppId will be displayed at the bottom of the notification. 47 | To find out how to define the AppID, run "Get-StartApps". You get a list of possible values. 48 | You get more informatiosn about the AppID here https://docs.microsoft.com/en-us/windows/win32/shell/appids and here https://toastit.dev/2018/02/04/burnttoast-appid-installer/. 49 | 50 | Place the script in a local folder on the VDA, together with the CWA.png file. Create a folder "Logging" with write permissions for the users. 51 | Run the script as a logon script or with Citrix WEM external task. 52 | 53 | Windows client CR versions: 21.3.1.25 (2103.1), 21.5.0.48 (2105), 21.6.0.47 (2106), 21.8.0.4026 (2108) 54 | Windows client LTSR version: 19.12.3000.6, 19.12.4000.19, 19.12.5000.3 55 | Mac client versions: 21.06.0.31 (2106), 21.07.0.4 (2107), 21.8.1.20 (2108.1) 56 | Linux client versions: 21.4.0.11 (2104), 21.6.0.28 (2106), 21.8.0.40 (2108) 57 | 58 | Version: 1.1 59 | Author: Dennis Mohrmann <@mohrpheus78> 60 | Creation Date: 2021-02-19 61 | Purpose/Change: 62 | 2021-02-20 Inital version 63 | 2021-02-21 Added Language, Added BurntToast text 64 | 2021-02-22 Added BurntToast text 65 | 2021-02-23 Added Linux client 66 | 2021-02-28 Added logging 67 | 2021-03-04 Added mail button 68 | 2021-09-27 Changed client versions 69 | #> 70 | 71 | [CmdletBinding()] 72 | 73 | param( 74 | [Parameter( 75 | Mandatory = $false)] 76 | [version]$WindowsClientMin = "21.8.0.4026", # define minimum client version here 77 | 78 | [Parameter( 79 | Mandatory = $false)] 80 | [version]$MacClientMin = "21.8.1.20", # define minimum client version here 81 | 82 | [Parameter( 83 | Mandatory = $false)] 84 | [version]$LinuxClientMin = "21.8.0.40", # define minimum client version here 85 | 86 | [Parameter( 87 | Mandatory = $true)] 88 | [ValidateNotNull()] 89 | [ValidateNotNullOrEmpty()] 90 | [String]$MailButton 91 | ) 92 | 93 | #==================================================================================== 94 | Function WriteLog { 95 | 96 | [CmdletBinding()] 97 | 98 | Param( 99 | [Parameter( 100 | Mandatory=$true, Position = 1)] 101 | [AllowEmptyString()][String]$Text, 102 | [Parameter( 103 | Mandatory=$true, Position = 2)] 104 | [AllowEmptyString()][String]$LogFile 105 | ) 106 | 107 | begin {} 108 | 109 | process { 110 | if ( $Text -eq "" ) { 111 | Add-Content $LogFile -value ("") # Write an empty line 112 | } Else { 113 | Add-Content $LogFile -value ($Text) 114 | } 115 | } 116 | 117 | end {} 118 | } 119 | #==================================================================================== 120 | 121 | # General variables 122 | $DateTime = (Get-Date -format dd-MM-yyyy) + " " + (Get-Date -format HH:mm:ss) 123 | $Language = [CultureInfo]::InstalledUICulture.Name 124 | $CitrixSessionID = Get-ChildItem -Path "HKCU:\Volatile Environment" -Name 125 | $CitrixClientName = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Name 126 | [version]$CitrixClientVersion = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Version 127 | 128 | # Citrix Client platform 129 | $ClientProductId=(Get-ItemProperty HKLM:\Software\Citrix\ICA\Session\$CitrixSessionID\Connection -name ClientProductId).ClientproductId 130 | if ($ClientProductId -eq 1) {$ClientPlatform="Windows"} 131 | if ($ClientProductId -eq 81) {$ClientPlatform="Linux"} 132 | if ($ClientProductId -eq 82) {$ClientPlatform="Mac"} 133 | if ($ClientProductId -eq 257) {$ClientPlatform="HTML5"} 134 | 135 | # BurntToast variables 136 | $BTAppIcon = New-BTImage -Source "$PSScriptRoot\CWA.png" -AppLogoOverride 137 | $BTAppId = "{7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}\SuL\Scripts\Notifications\CWA.png" 138 | $BTAudio = New-BTAudio -Source ms-winsoundevent:Notification.IM 139 | if ($Language -eq "de-DE") { 140 | $BTText1 = New-BTText -Text "Ihr Citrix Client ist nicht aktuell!" 141 | $BTText2 = New-BTText -Text "$ClientPlatform Client Version $CitrixClientVersion." 142 | $BTText3 = New-BTText -Text "Sie finden den aktuellen Client unter https://workspace.app" 143 | } 144 | else { 145 | $BTText1 = New-BTText -Text "Your Citrix Client is out of date!" 146 | $BTText2 = New-BTText -Text "$ClientPlatform Client Version $CitrixClientVersion." 147 | $BTText3 = New-BTText -Text "You find the current client on https://workspace.app" 148 | } 149 | 150 | if ($ClientPlatform -eq "HTML5") { 151 | if ($Language -eq "de-DE") { 152 | $BTText1 = New-BTText -Text "Sie benutzen den Citrix HTML client!" 153 | $BTText2 = New-BTText -Text "Bitte einen vollwertigen Citrix Client installieren." 154 | $BTText3 = New-BTText -Text "Sie finden einen aktuellen Client unter https://workspace.app" 155 | } 156 | else { 157 | $BTText1 = New-BTText -Text "You use the Citrix HTML client!" 158 | $BTText2 = New-BTText -Text "Please install a suitable client for your device." 159 | $BTText3 = New-BTText -Text "You find a current client on https://workspace.app" 160 | } 161 | } 162 | 163 | $BTBinding = New-BTBinding -Children $BTText1, $BTText2, $BTText3 -AppLogoOverride $BTAppIcon 164 | $BTVisual = New-BTVisual -BindingGeneric $BTBinding 165 | $BTContent = New-BTContent -Visual $BTVisual -Audio $BTAudio -Duration Long 166 | # Mailbutton 167 | if ($MailButton -eq "true") { 168 | $MailBody = "User: $ENV:username%0D%0AClient: $CitrixClientName%0D%0A$ClientPlatform Client version: $CitrixClientVersion" 169 | $MailSubject = "Citrix Client check" 170 | $MailContent = "mailto:helpdesk@domain.com?Subject=$MailSubject&Body=$MailBody" 171 | $BTButton = New-BTButton -Content "Contact Support" -Arguments $MailContent 172 | $BTAction = New-BTAction -Buttons $BTButton 173 | $BTContent = New-BTContent -Visual $BTVisual -Audio $BTAudio -Duration Long -Actions $BTAction 174 | } 175 | New-BTAppId -AppId $BTAppId 176 | 177 | # Logging 178 | $LogFile = "$PSScriptRoot\Logging\$CitrixClientName-Citrix client check.log" 179 | New-Item $LogFile -ItemType "file" -force | Out-Null 180 | WriteLog "START SCRIPT" $LogFile 181 | WriteLog "$DateTime" $LogFile 182 | WriteLog "Clientname: $CitrixClientName" $LogFile 183 | WriteLog "Platform: $ClientPlatform" $LogFile 184 | 185 | # Citrix client platform HTML5 186 | if ($ClientPlatform -eq "HTML5") { 187 | WriteLog "Platform: $ClientPlatform" $LogFile 188 | Submit-BTNotification -Content $BTContent -AppId $BTAppId 189 | } 190 | 191 | switch ($ClientPlatform) 192 | { 193 | 'Windows' { 194 | WriteLog "Minimum client version: $WindowsClientMin" $LogFile 195 | WriteLog "Current client version: $CitrixClientVersion" $LogFile 196 | if ($CitrixClientVersion -lt $WindowsClientMin) { 197 | Submit-BTNotification -Content $BTContent -AppId $BTAppId 198 | } 199 | } 200 | 201 | 'Mac' { 202 | WriteLog "Minimum client version: $MacClientMin" $LogFile 203 | WriteLog "Current client version: $CitrixClientVersion" $LogFile 204 | if ($CitrixClientVersion -lt $MacClientMin) { 205 | Submit-BTNotification -Content $BTContent -AppId $BTAppId 206 | } 207 | } 208 | 209 | 'Linux' { 210 | WriteLog "Minimum client version: $LinuxClientMin" $LogFile 211 | WriteLog "Current client version: $CitrixClientVersion" $LogFile 212 | if ($CitrixClientVersion -lt $LinuxClientMin) { 213 | Submit-BTNotification -Content $BTContent -AppId $BTAppId 214 | } 215 | } 216 | } -------------------------------------------------------------------------------- /PVS Admin Toolkit/Hypervisor/Configure Hypervisor.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will configure a hypervisor and the appropriate admin account to connect to the host and perform actions like start the PVS master VM 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to configure a hypervisor an admin account with a password and store this information in text files, the password is encrypted 7 | 8 | .NOTES 9 | 10 | Author: Dennis Mohrmann <@mohrpheus78> 11 | Creation Date: 2022-02-06 12 | #> 13 | 14 | 15 | # RunAs Admin 16 | function Use-RunAs 17 | { 18 | # Check if script is running as Administrator and if not elevate it 19 | # Use Check Switch to check if admin 20 | 21 | param([Switch]$Check) 22 | 23 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 24 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 25 | 26 | if ($Check) { return $IsAdmin } 27 | 28 | if ($MyInvocation.ScriptName -ne "") 29 | { 30 | if (-not $IsAdmin) 31 | { 32 | try 33 | { 34 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 35 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 36 | } 37 | catch 38 | { 39 | Write-Warning "Error - Failed to restart script elevated" 40 | break 41 | } 42 | exit 43 | } 44 | } 45 | } 46 | 47 | Use-RunAs 48 | 49 | # Variablen 50 | $RootFolder = Split-Path -Path $PSScriptRoot 51 | $HypervisorConfig = "$PSScriptRoot\Hypervisor.xml" 52 | $HypervisorSelection = New-Object PSObject 53 | $CredentialConfig = (Get-ChildItem -Path $PSScriptRoot -Filter Credentials-$env:username*.xml).Name 54 | $CredentialSelection = New-Object PSObject 55 | 56 | # Show Menu 57 | function Show-Menu 58 | { 59 | param ( 60 | [string]$Title = 'Hypervisor' 61 | ) 62 | Clear-Host 63 | Write-Host "======== $Title ========" 64 | Write-Host `n 65 | Write-Host "1: VMWare ESX" 66 | Write-Host "2: XenServer (Citrix Hypervisor)" 67 | #Write-Host "3: Nutanix AHV" 68 | Write-Host `n 69 | } 70 | 71 | # Hypervisor selection 72 | Write-Host -ForegroundColor Cyan "Checking current configuration..."`n 73 | IF (Test-Path -Path $HypervisorConfig) { 74 | Write-Host -ForegroundColor Cyan "Configuration found:" 75 | $HypervisorXML = Import-Clixml -Path $HypervisorConfig 76 | $Hypervisor = $HypervisorXML.Hypervisor 77 | $HypervisorHost = $HypervisorXML.Host 78 | 79 | IF ($HypervisorXML.Hypervisor) { 80 | Write-Host -ForegroundColor Yellow "Hypervisor - $Hypervisor" 81 | Write-Host -ForegroundColor Yellow "Host - $HypervisorHost" 82 | $title = "" 83 | $message = "Hypervisor type already configured, do you want to use the hypervisor type '$Hypervisor'?" 84 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 85 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 86 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 87 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 88 | switch ($choice) { 89 | 0 { 90 | $Answer1 = 'Yes' 91 | } 92 | 1 { 93 | $Answer1 = 'No' 94 | } 95 | } 96 | Write-Host `n 97 | } 98 | } 99 | IF ($Answer1 -eq "Yes") { 100 | $Hypervisor = $HypervisorXML.Hypervisor 101 | Add-member -inputobject $HypervisorSelection -MemberType NoteProperty -Name "Hypervisor" -Value $Hypervisor -Force 102 | } 103 | 104 | ELSE { 105 | Show-Menu -Title 'Hypervisor configuration' 106 | $Selection = Read-Host "Which Hypervisor do you use?" 107 | switch ($Selection) 108 | { 109 | '1' {$Hypervisor = 'ESX'} 110 | '2' {$Hypervisor = 'Xen'} 111 | #'3' {$Hypervisor = 'AHV'} 112 | } 113 | Add-member -inputobject $HypervisorSelection -MemberType NoteProperty -Name "Hypervisor" -Value $Hypervisor -Force 114 | 115 | <# 116 | # Prepare for module installation 117 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 118 | IF (!(Test-Path -Path "C:\Program Files\PackageManagement\ProviderAssemblies\nuget")) { 119 | Find-PackageProvider -Name 'Nuget' -ForceBootstrap -IncludeDependencies } 120 | try { 121 | set-PSRepository -Name PSGallery -InstallationPolicy Trusted } 122 | catch { 123 | Write-Output "Error: $($PSItem.ToString())" 124 | Write-Host "Something went wrong, check your PSGallery settings or proxy settings" 125 | Read-Host "Presse ENTER to exit" 126 | BREAK 127 | } 128 | #> 129 | 130 | # Hypervisor name or IP address 131 | Write-Host "Configure your hypervisor IP address or hostname (vCenter/ESXi/XenServer/AHV) once" 132 | $HypervisorHost = Read-Host "IP address or hostname (DNS name resolution required)" 133 | Add-member -inputobject $HypervisorSelection -MemberType NoteProperty -Name "Host" -Value $HypervisorHost -Force 134 | $HypervisorSelection | Export-Clixml $HypervisorConfig 135 | } 136 | 137 | # Hypervisor admin account 138 | Write-Host -ForegroundColor Cyan "Checking current credentials..." 139 | IF (([string]::ISNullOrEmpty( $CredentialConfig) -eq $False) -or ($Answer1 -eq "Yes")) { 140 | IF (!(Get-ChildItem -Path $PSScriptRoot -Filter Credentials-$env:username*.xml)) { 141 | Write-Host -ForegroundColor Cyan "No credentials found, configure your credentials" 142 | } 143 | ELSE { 144 | Write-Host -ForegroundColor Cyan "Credentials found:" 145 | $CredentialsXML = Import-Clixml -Path $PSScriptRoot\$CredentialConfig 146 | $Username = $CredentialsXML.UserName 147 | 148 | IF ($CredentialsXML.UserName) { 149 | Write-Host -ForegroundColor Yellow "Credentials - $Username" 150 | $title = "" 151 | $message = "Username already configured, do you want to use the account '$Username' with the current credentials?`nIf you want to use other credentials or change the current password, select 'No'" 152 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 153 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 154 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 155 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 156 | switch ($choice) { 157 | 0 { 158 | $Answer2 = 'Yes' 159 | } 160 | 1 { 161 | $Answer2 = 'No' 162 | } 163 | } 164 | Write-Host `n 165 | IF ($Answer2 -eq "Yes") { 166 | $Username = $CredentialsXML.UserName 167 | Add-member -inputobject $CredentialSelection -MemberType NoteProperty -Name "UserName" -Value $UserName -Force 168 | } 169 | ELSE { 170 | Write-Host -ForegroundColor Yellow "Configure your Hypervisor admin account and password once, the password is encrypted and only valid for the current user account!" 171 | } 172 | } 173 | } 174 | } 175 | 176 | IF (!(Get-ChildItem -Path $PSScriptRoot -Filter Credentials-$env:username*.xml) -or ($Answer2 -eq "No")) { 177 | 178 | IF ($Hypervisor -eq 'ESX') { 179 | Write-Host `n 180 | Write-Host -ForegroundColor Yellow "Enter your vSphere Administrator account (DOMAIN\Admin) or ESXi Account" 181 | Read-Host "Press ENTER to continue..." 182 | IF ($CredentialsXML.UserName) { 183 | Write-Host "Do you want to keep the current user '$UserName'?" 184 | $User = Read-Host "( Y / N )" 185 | IF ($User -eq 'Y') { 186 | Get-Credential -UserName $UserName -Message "Enter vSphere Administrator account (DOMAIN\Admin) or ESXi Account " | Export-CliXml -Path "$PSScriptRoot\Credentials-$env:username-ESX.xml" 187 | #Add-member -inputobject $CredentialSelection -MemberType NoteProperty -Name "UserName" -Value $UserName -Force 188 | } 189 | } 190 | ELSE { 191 | Get-Credential -UserName $ENV:UserName@$ENV:UserDNSDomain -Message "Enter vSphere Administrator account (DOMAIN\Admin) or ESXi Account " | Export-CliXml -Path "$PSScriptRoot\Credentials-$env:username-ESX.xml" 192 | } 193 | # Install Powershell module 194 | IF (!(Get-Module -ListAvailable -Name VMWare.PowerCLI)) { 195 | try { 196 | Install-Module VMWare.PowerCLI -Scope AllUsers -Force 197 | } 198 | catch { 199 | Write-Host -ForegroundColor Red "Error - Failed to install VMWare PowerCLI module (Error: $($Error[0])), download and install the VMWare PowerCLI module!" 200 | Read-Host 201 | break 202 | } 203 | } 204 | Write-Host -ForegroundColor Yellow "Importing VMWare Powershell module, please wait..." 205 | try { 206 | Import-Module -Name VMWare.PowerCLI 207 | } 208 | catch { 209 | Write-Host -ForegroundColor Red "Error - Failed to import VMWare PowerCLI module (Error: $($Error[0]))" 210 | Read-Host 211 | break 212 | } 213 | } 214 | 215 | IF ($Hypervisor -eq 'Xen') { 216 | Write-Host `n 217 | Write-Host -ForegroundColor Yellow "Enter your Domain Administrator account (DOMAIN\Admin) or root" 218 | Read-Host "Press ENTER to continue..." 219 | Get-Credential -UserName root -Message "Domain Administrator account (DOMAIN\Admin) or root " | Export-CliXml -Path "$PSScriptRoot\Credentials-$env:username-Xen.xml" 220 | # Check Powershell module 221 | IF (!(Get-Module -ListAvailable -Name XenServerPSModule)) { 222 | Write-Host -ForegroundColor Red "XenServer Powershell module 'XenServerPSModule' not found, download the XenServer SDK and install the module: https://www.xenserver.com/downloads" 223 | Read-Host 224 | break 225 | } 226 | } 227 | 228 | <# 229 | IF ($Hypervisor -eq 'AHV') { 230 | #Write-Host -ForegroundColor Yellow "Enter your Domain Administrator account (DOMAIN\Admin) or root" 231 | Write-Host `n 232 | $AHVAdmin = Read-Host "Enter your Domain Administrator account (DOMAIN\Admin) or AHV Admin account" 233 | $AHVPassword = Read-Host "Password" 234 | $AHVAdminFile = "$PSScriptRoot\Admin-AHV.txt" 235 | $AHVAdmin | Out-File $AHVAdminFile 236 | $KeyFile = "$PSScriptRoot\AES.key" 237 | $Key = New-Object Byte[] 24 238 | [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key) 239 | $Key | out-file $KeyFile 240 | $AHVPasswordFile = "$PSScriptRoot\Password-AHV.txt" 241 | $KeyFile = "$PSScriptRoot\AES.key" 242 | $Key = Get-Content $KeyFile 243 | $AHVPassword = $AHVPassword | ConvertTo-SecureString -AsPlainText -Force 244 | $AHVPassword | ConvertFrom-SecureString -key $Key | Out-File $AHVPasswordFile 245 | Read-Host "Press ENTER to continue..." 246 | # Install Powershell module 247 | IF ($PSVersionTable.PSVersion -lt "7.0") { 248 | Write-Host -ForegroundColor Red "You need Powershell 7.0 or higher to use the Nutanix Powershell module, please install the recent version of Powershell" 249 | Read-Host "Press ENTER to exit" 250 | BREAK 251 | } 252 | IF (!(Get-Module -ListAvailable -Name Nutanix.Cli)) { 253 | Install-Module Nutanix.Cli -Scope AllUsers -Force 254 | } 255 | } 256 | #> 257 | } 258 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS/Create PVS devices.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will configure a hypervisor and the appropriate admin account to connect to the host and perform actions like start the PVS master VM 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to configure a hypervisor an admin account with a password and store this information in text files, the password is encrypted 7 | 8 | .NOTES 9 | 10 | Author: Dennis Mohrmann <@mohrpheus78> 11 | Creation Date: 2022-02-06 12 | #> 13 | 14 | # RunAs Admin 15 | function Use-RunAs 16 | { 17 | # Check if script is running as Administrator and if not elevate it 18 | # Use Check Switch to check if admin 19 | 20 | param([Switch]$Check) 21 | 22 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 23 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 24 | 25 | if ($Check) { return $IsAdmin } 26 | 27 | if ($MyInvocation.ScriptName -ne "") 28 | { 29 | if (-not $IsAdmin) 30 | { 31 | try 32 | { 33 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 34 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 35 | } 36 | catch 37 | { 38 | Write-Warning "Error - Failed to restart script elevated" 39 | break 40 | } 41 | exit 42 | } 43 | } 44 | } 45 | 46 | Use-RunAs 47 | 48 | # Check if PVS SnapIn is available 49 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 50 | try { 51 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 52 | } 53 | catch { 54 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 55 | } 56 | 57 | # Variables 58 | $RootFolder = Split-Path -Path $PSScriptRoot 59 | $Date = Get-Date -UFormat "%d.%m.%Y" 60 | $Log = "$RootFolder\Logs\Create PVS devices.log" 61 | $PVSConfig = Import-Clixml "$RootFolder\PVS\PVS.xml" 62 | $DHCPConfig = Import-Clixml "$RootFolder\PVS\DHCP.xml" 63 | 64 | # Start logging 65 | Start-Transcript $Log | Out-Null 66 | 67 | $ScriptStart = Get-Date 68 | 69 | # Check if PVS SnapIn is available 70 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 71 | try { 72 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 73 | } 74 | catch { 75 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 76 | } 77 | 78 | # Get PVS servers 79 | $PVSServerIP = Get-PvsServer | Select-Object IP 80 | $PVSServer1 = $PVSServerIP[0] 81 | $PVSServer2 = $PVSServerIP[1] 82 | $IPPVSServer1 = ($PVSServer1.Ip).IPAddressToString 83 | $IPPVSServer2 = ($PVSServer2.Ip).IPAddressToString 84 | $PVSServers = ($IPPVSServer1 + ',' + $IPPVSServer2).tostring() 85 | # Get PVS site 86 | $SiteName = (Get-PvsSite).SiteName 87 | 88 | # New devices 89 | Write-Host -ForegroundColor Yellow "New PVS devices" `n 90 | 91 | # Get all collections 92 | $AllCollections = Get-PvsCollection -SiteName $SiteName 93 | 94 | # Add property "ID" to object 95 | $ID = 1 96 | $AllCollections | ForEach-Object { 97 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 98 | $ID += 1 99 | } 100 | 101 | # Show menu to select vDisk 102 | Write-Host "Available device collections:" `n 103 | $ValidChoices = 1..($AllCollections.Count) 104 | $Menu = $AllCollections | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name)} 105 | #$Menu = $AllCollections 106 | $Menu | Out-Host 107 | Write-Host 108 | $Collection = Read-Host -Prompt 'Select the device collection for your new devices' 109 | 110 | $Collection = $AllCollections | Where-Object {$_.ID -eq $Collection} 111 | if ($Collection.ID -notin $ValidChoices) { 112 | Write-Host -ForegroundColor Red "Selected store not found, aborting!" 113 | Read-Host "Press any key to exit" 114 | BREAK 115 | } 116 | 117 | $CollectionName = $Collection.Name 118 | Write-Host "" 119 | 120 | # Get all vDisks 121 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 122 | 123 | # Add property "ID" to object 124 | $ID = 1 125 | $AllvDisks | ForEach-Object { 126 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 127 | $ID += 1 128 | } 129 | 130 | # Show menu to select vDisk 131 | Write-Host "Available vDisks:" `n 132 | $ValidChoices = 1..($AllvDisks.Count) 133 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 134 | $Menu | Out-Host 135 | Write-Host 136 | $vDisk = Read-Host -Prompt 'Select the vDisk for your new devices' 137 | 138 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 139 | if ($vDisk.ID -notin $ValidChoices) { 140 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 141 | Read-Host "Press any key to exit" 142 | BREAK 143 | } 144 | $vDiskName = $vDisk.Name 145 | $StoreName = $vDisk.StoreName 146 | Write-Host "" 147 | 148 | # Get AD OU 149 | Write-Host -ForegroundColor Yellow "Configuring the organization unit (OU) for the new PVS devices" `n 150 | $PVSDevice = (Get-PvsDevice -SiteName $SiteName -CollectionName $CollectionName | Select-Object -First 1).DeviceName 151 | if ($PVSDevice) { 152 | if (Get-WindowsFeature | Where-Object {$_.Name -match "RSAT-AD-PowerShell" -and $_.Installed -match "false"}) { 153 | Install-WindowsFeature -Name "RSAT-AD-PowerShell" 154 | } 155 | $OU = (Get-ADComputer -Identity $PVSDevice -Properties CanonicalName).CanonicalName 156 | $OU = $OU -replace "$env:USERDNSDOMAIN/"," " -replace "/$PVSDevice"," " 157 | $title = "" 158 | $message = "A PVS device was found in the device collection, do you want to use the same OU '$OU' for the new devices?" 159 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 160 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 161 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 162 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 163 | switch ($choice) { 164 | 0 { 165 | $Answer = 'Yes' 166 | } 167 | 1 { 168 | $Answer = 'No' 169 | } 170 | } 171 | Write-Host `n 172 | if ($Answer -eq "No") { 173 | $OU = Read-Host "Configure the organization unit for the PVS devices in AD, use the canonical name like 'Servers/Citrix/CVAD-Worker' with the domain name" 174 | Write-Host `n 175 | } 176 | else { 177 | Write-Host -ForegroundColor Yellow "Using OU '$OU'" 178 | } 179 | } 180 | else { 181 | $OU = Read-Host "Configure the organization unit for the PVS devices in AD, use the canonical name like 'Servers/Citrix/CVAD-Worker' with the domain name" 182 | Write-Host `n 183 | } 184 | pause 185 | 186 | # Read CSV 187 | $CSVpath = "$RootFolder\PVS\VDA.csv" 188 | $csv = Import-Csv $CSVpath -Delimiter ";" 189 | $csvHostnames = $CSV.Hostname 190 | 191 | # DHCP reservation 192 | Write-Host -ForegroundColor Yellow "Configuring DHCP reservations" 193 | foreach ($Hostnames in $CSV) { 194 | $Hostname = $Hostnames.Hostname 195 | $Mac = $Hostnames.Mac 196 | $MacReplace = $Mac -replace (":", "") 197 | $IP = $Hostnames.IP 198 | 199 | IF (!(Get-DhcpServerv4Reservation -ComputerName $DHCPConfig.Host -ScopeId $DHCPConfig.Scope | Where-Object {$_.ipaddress -eq $IP})) { 200 | Try { 201 | Add-DhcpServerv4Reservation -ComputerName $DHCPConfig.Host -ScopeId $DHCPConfig.Scope -IPAddress $IP -ClientId $MacReplace -Description $Hostname -Name $Hostname -Type Dhcp 202 | Write-Host -ForegroundColor Green "DHCP reservations successfully created, check logfile '$log'"`n 203 | } 204 | catch { 205 | write-warning "Error: $_." 206 | } 207 | 208 | if ($DHCPConfig.TFTP) { 209 | Try { 210 | Set-DhcpServerv4OptionValue -ComputerName $DHCPConfig.Host -ReservedIP $IP -OptionId 66 -Value $DHCPConfig.TFTP -ErrorAction SilentlyContinue 211 | Write-Host -ForegroundColor Green "DHCP option ID 66 successfully created"`n 212 | } 213 | catch { 214 | write-warning "Error: $_." 215 | } 216 | } 217 | 218 | if ($DHCPConfig.TFTPBootfile) { 219 | Try { 220 | Set-DhcpServerv4OptionValue -ComputerName $DHCPConfig.Host -ReservedIP $IP -OptionId 67 -Value $DHCPConfig.TFTPBootfile -ErrorAction SilentlyContinue 221 | Write-Host -ForegroundColor Green "DHCP option ID 67 successfully created"`n 222 | } 223 | catch { 224 | write-warning "Error: $_." 225 | } 226 | } 227 | 228 | if ($DHCPConfig.TFTPBootfile -eq "pvsnbpx64.efi") { 229 | Try { 230 | Set-DhcpServerv4OptionValue -ComputerName $DHCPConfig.Host -ReservedIP $IP -OptionId 11 -Value $PVSServers.split(",") -ErrorAction SilentlyContinue 231 | Write-Host -ForegroundColor Green "DHCP option ID 11 successfully created"`n 232 | } 233 | catch { 234 | write-warning "Error: $_." 235 | } 236 | } 237 | } 238 | ELSE { 239 | Write-Host -ForegroundColor Red "DHCP reservation for '$Hostname' already exists, skipping!"`n 240 | } 241 | } 242 | # Replicate to failover partner 243 | Try { 244 | Invoke-DhcpServerv4FailoverReplication -ComputerName $DHCPConfig.Host -ScopeID $DHCPConfig.Scope -force -EA SilentlyContinue | Out-Null 245 | Write-Host -ForegroundColor Green "DHCP scope successfully replicated to failiver partner"`n 246 | } 247 | catch { 248 | write-warning "Error: $_." 249 | } 250 | 251 | # Create PVS devices and computer AD accounts 252 | Write-Host -ForegroundColor Yellow "Creating PVS devices and computer AD accounts" 253 | foreach ($Hostnames in $CSV) { 254 | $Hostname = $Hostnames.Hostname 255 | $Mac = $Hostnames.Mac 256 | $MacReplace = $Mac -replace (":", "-") 257 | 258 | IF (!(Get-PvsDevice | Where-Object {$_.Name -eq $Hostname})) { 259 | Try { 260 | New-PvsDevice -SiteName $SiteName -CollectionName $CollectionName -DeviceName $Hostname -DeviceMac $MacReplace | Out-Null 261 | Add-PvsDeviceToDomain -DeviceName $Hostnames.Hostname -Domain $ENV:userdnsdomain -OrganizationUnit $OU | Out-Null 262 | Add-PvsDiskLocatorToDevice -DiskLocatorName $vDiskName -DeviceName $Hostnames.Hostname -SiteName $SiteName -StoreName $StoreName 263 | Write-Host -ForegroundColor Green "New PVS device '$Hostname' successfully created, check logfile '$log'"`n 264 | } 265 | catch { 266 | write-warning "Error: $_." 267 | } 268 | } 269 | ELSE { 270 | Write-Host -ForegroundColor Red "PVS device '$Hostname' already exists, skipping!"`n 271 | } 272 | } 273 | 274 | # Stop Logging 275 | $ScriptEnd = Get-Date 276 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 277 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 278 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds"`n 279 | 280 | Stop-Transcript | Out-Null 281 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 282 | Set-Content -Value $Content -Path $Log 283 | Rename-Item -Path $Log -NewName "Create PVS devices-$CollectionName-$Date.log" -EA SilentlyContinue 284 | 285 | & "$RootFolder\PVS\Create PVS VM.ps1" 286 | 287 | Read-Host "Press any key to exit" -------------------------------------------------------------------------------- /PVS Admin Toolkit/PVS Admin Toolkit.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will create a systray icon with a menu to launch the other PVS admin scripts. 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to create a systray icon to launch the PVS admin scripts in the folder "C:\Program Files (x86)\Scripts". 7 | 8 | .NOTES 9 | If you want to change the root folder you have to modify the shortcut. 10 | 11 | Author: Dennis Mohrmann <@mohrpheus78> 12 | Creation Date: 2021-10-27 13 | Purpose/Change: 14 | 2021-10-30 Inital version 15 | 2022-02-06 Added Windows Updates and configuration menu 16 | 2022-02-18 Added Evergreen 17 | 2022-12-20 Changed Evergreen to my own Evergreen scripts 18 | #> 19 | 20 | # Force garbage collection just to start slightly lower RAM usage 21 | [System.GC]::Collect() 22 | 23 | # Declare assemblies 24 | [System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | out-null 25 | [System.Reflection.Assembly]::LoadWithPartialName('presentationframework') | out-null 26 | [System.Reflection.Assembly]::LoadWithPartialName('System.Drawing') | out-null 27 | [System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null 28 | 29 | # Add an icon to the systray 30 | $icon = [System.Drawing.Icon]::ExtractAssociatedIcon("C:\Program Files\Citrix\Provisioning Services\MCLI.exe") 31 | 32 | # Create object for the systray 33 | $Systray_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon 34 | 35 | # Text displayed when you pass the mouse over the systray icon 36 | $Systray_Tool_Icon.Text = "PVS Admin Toolkit" 37 | 38 | # Systray icon 39 | $Systray_Tool_Icon.Icon = $icon 40 | $Systray_Tool_Icon.Visible = $true 41 | 42 | # Create object for the systray 43 | $contextmenu = New-Object System.Windows.Forms.ContextMenuStrip 44 | 45 | # Create Menus 46 | $Menu_1 = $contextmenu.Items.Add("PVS Toolkit Configuration"); 47 | $Menu_1.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Configuration.png") 48 | 49 | $Menu_2 = $contextmenu.Items.Add("Launch PVS Console"); 50 | $Menu_2.Image = $icon 51 | 52 | $Menu_3 = $contextmenu.Items.Add("vDisk Maintenance"); 53 | $Menu_3.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\New PVS vDisk version.png") 54 | 55 | $Menu_4 = $contextmenu.Items.Add("Windows Update"); 56 | $Menu_4.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\Windows Update.png") 57 | 58 | $Menu_5 = $contextmenu.Items.Add("Evergreen"); 59 | $Menu_5.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Evergreen\Evergreen.ico") 60 | 61 | $Menu_6 = $contextmenu.Items.Add("Create new PVS devices"); 62 | $Menu_6.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\PVS\Devices.png") 63 | 64 | $Menu_7 = $contextmenu.Items.Add("Document vDisk versions"); 65 | $Menu_7.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Documentation\PVS vDisk versions.png") 66 | 67 | $Menu_8 = $contextmenu.Items.Add("Merge vDisk"); 68 | $Menu_8.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Merge\Merge PVS vDisk.png") 69 | 70 | $Menu_9 = $contextmenu.Items.Add("Replicate vDisk"); 71 | $Menu_9.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Replication\Replicate PVS vDisk.png") 72 | 73 | $Menu_10 = $contextmenu.Items.Add("Export all vDisks (XML)"); 74 | $Menu_10.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Export\Export PVS vDisk.png") 75 | 76 | $Menu_11 = $contextmenu.Items.Add("Shrink vDisk"); 77 | $Menu_11.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Shrink\Shrink PVS vDisk.png") 78 | 79 | $Menu_12 = $contextmenu.Items.Add("Remove log files"); 80 | $Menu_12.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Logs.ico") 81 | 82 | $Menu_Exit = $contextmenu.Items.Add("Exit"); 83 | $Menu_Exit.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Exit.png") 84 | 85 | #Sub menus for Menu 1 86 | $Menu1_SubMenu1 = New-Object System.Windows.Forms.ToolStripMenuItem 87 | $Menu1_SubMenu1.Text = "Hypervisor configuration" 88 | $Menu1_SubMenu1.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Hypervisor\Hypervisor.png") 89 | $Menu_1.DropDownItems.Add($Menu1_SubMenu1) 90 | 91 | $Menu1_SubMenu2 = New-Object System.Windows.Forms.ToolStripMenuItem 92 | $Menu1_SubMenu2.Text = "PVS configuration" 93 | $Menu1_SubMenu2.Image = $Icon 94 | $Menu_1.DropDownItems.Add($Menu1_SubMenu2) 95 | 96 | $Menu1_SubMenu3 = New-Object System.Windows.Forms.ToolStripMenuItem 97 | $Menu1_SubMenu3.Text = "Evergreen configuration" 98 | $Menu1_SubMenu3.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Evergreen\Evergreen.ico") 99 | $Menu_1.DropDownItems.Add($Menu1_SubMenu3) 100 | 101 | #Sub menus for Menu 3 102 | $Menu3_SubMenu1 = New-Object System.Windows.Forms.ToolStripMenuItem 103 | $Menu3_SubMenu1.Text = "New vDisk version" 104 | $Menu3_SubMenu1.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\New PVS vDisk version.png") 105 | $Menu_3.DropDownItems.Add($Menu3_SubMenu1) 106 | 107 | $Menu3_SubMenu2 = New-Object System.Windows.Forms.ToolStripMenuItem 108 | $Menu3_SubMenu2.Text = "Promote vDisk version" 109 | $Menu3_SubMenu2.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\Promote PVS vDisk version.png") 110 | $Menu_3.DropDownItems.Add($Menu3_SubMenu2) 111 | 112 | #Sub menu for Menu 4 113 | $Menu4_SubMenu1 = New-Object System.Windows.Forms.ToolStripMenuItem 114 | $Menu4_SubMenu1.Text = "Install Windows Updates on vDisk" 115 | $Menu4_SubMenu1.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\Windows Update.png") 116 | $Menu_4.DropDownItems.Add($Menu4_SubMenu1) 117 | 118 | $Menu4_SubMenu2 = New-Object System.Windows.Forms.ToolStripMenuItem 119 | $Menu4_SubMenu2.Text = "Import scheduled tasks for Windows Update" 120 | $Menu4_SubMenu2.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\Scheduled Task.png") 121 | $Menu_4.DropDownItems.Add($Menu4_SubMenu2) 122 | 123 | #Sub menu for Menu 5 124 | $Menu5_SubMenu1 = New-Object System.Windows.Forms.ToolStripMenuItem 125 | $Menu5_SubMenu1.Text = "Launch Evergreen script on vDisk" 126 | $Menu5_SubMenu1.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\Evergreen\Evergreen.ico") 127 | $Menu_5.DropDownItems.Add($Menu5_SubMenu1) 128 | 129 | $Menu5_SubMenu2 = New-Object System.Windows.Forms.ToolStripMenuItem 130 | $Menu5_SubMenu2.Text = "Import scheduled tasks for executing Evergreen" 131 | $Menu5_SubMenu2.Image = [System.Drawing.Bitmap]::FromFile("$PSScriptRoot\vDisk Maintenance\Scheduled Task.png") 132 | $Menu_5.DropDownItems.Add($Menu5_SubMenu2) 133 | 134 | # Add the context menu object to the main systray tool object 135 | $Systray_Tool_Icon.ContextMenuStrip = $contextmenu; 136 | 137 | # Action after clicking 138 | $Menu1_SubMenu1.add_Click({ 139 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\Hypervisor\Configure Hypervisor.ps1`"" 140 | start-process powershell.exe -ArgumentList $args 141 | }) 142 | 143 | $Menu1_SubMenu2.add_Click({ 144 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\PVS\Configure PVS.ps1`"" 145 | start-process powershell.exe -ArgumentList $args 146 | }) 147 | 148 | $Menu1_SubMenu3.add_Click({ 149 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\Evergreen\Configure Evergreen.ps1`"" 150 | start-process powershell.exe -ArgumentList $args 151 | }) 152 | 153 | $Menu_2.add_Click({ 154 | start-process "C:\Program Files\Citrix\Provisioning Services Console\Console.msc" 155 | }) 156 | 157 | $Menu3_SubMenu1.add_Click({ 158 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\New PVS vDisk version.ps1`"" 159 | start-process powershell.exe -ArgumentList $args 160 | }) 161 | 162 | $Menu3_SubMenu2.add_Click({ 163 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\Promote PVS vDisk version.ps1`"" 164 | start-process powershell.exe -ArgumentList $args 165 | }) 166 | 167 | $Menu4_SubMenu1.add_Click({ 168 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\Start Windows Updates.ps1`"" 169 | start-process powershell.exe -ArgumentList $args 170 | }) 171 | 172 | $Menu4_SubMenu2.add_Click({ 173 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\Windows Updates Task.ps1`"" 174 | start-process powershell.exe -ArgumentList $args 175 | }) 176 | 177 | $Menu5_SubMenu1.add_Click({ 178 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\Start Evergreen.ps1`"" 179 | start-process powershell.exe -ArgumentList $args 180 | }) 181 | 182 | $Menu5_SubMenu2.add_Click({ 183 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Maintenance\Evergreen Task.ps1`"" 184 | start-process powershell.exe -ArgumentList $args 185 | }) 186 | 187 | $Menu_6.add_Click({ 188 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\PVS\Create PVS devices.ps1`"" 189 | start-process powershell.exe -ArgumentList $args 190 | }) 191 | 192 | $Menu_7.add_Click({ 193 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Documentation\PVS vDisk versions.ps1`"" 194 | start-process powershell.exe -ArgumentList $args 195 | }) 196 | 197 | $Menu_8.add_Click({ 198 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Merge\Merge PVS vDisk.ps1`"" 199 | start-process powershell.exe -ArgumentList $args 200 | }) 201 | 202 | $Menu_9.add_Click({ 203 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Replication\Replicate PVS vDisk.ps1`"" 204 | start-process powershell.exe -ArgumentList $args 205 | }) 206 | 207 | $Menu_10.add_Click({ 208 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Export\Export PVS vDisk.ps1`"" 209 | start-process powershell.exe -ArgumentList $args 210 | }) 211 | 212 | $Menu_11.add_Click({ 213 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\vDisk Shrink\Shrink PVS vDisk.ps1`"" 214 | start-process powershell.exe -ArgumentList $args 215 | }) 216 | 217 | $Menu_12.add_Click({ 218 | $args = "-NoProfile -NoLogo -WindowStyle Maximized -ExecutionPolicy Bypass -File `"$PSScriptRoot\Remove logs.ps1`"" 219 | start-process powershell.exe -ArgumentList $args 220 | }) 221 | 222 | # Make PowerShell Disappear 223 | $windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);' 224 | $asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru 225 | $null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0) 226 | 227 | # Action after click Exit 228 | $Menu_Exit.add_Click({ 229 | $Systray_Tool_Icon.Visible = $false 230 | Stop-Process $pid 231 | }) 232 | 233 | # Create an application context for it to all run within. 234 | $appContext = New-Object System.Windows.Forms.ApplicationContext 235 | [void][System.Windows.Forms.Application]::Run($appContext) 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Maintenance/Start Master.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will start a PVS master from a new vDIsk version 4 | 5 | .DESCRIPTION 6 | The purpose of the script is to start a PVS master on a hypervisor you defined earlier and to boot it from a new vDisk version 7 | 8 | .NOTES 9 | The variables have to be present in the XML files, configure your hypervisor with the configuration menu first! 10 | 11 | Version: 1.0 12 | Author: Dennis Mohrmann <@mohrpheus78> 13 | Creation Date: 2022-02-06 14 | Purpose/Change: 15 | 2022-02-06 Inital version 16 | 2022-02-10 Added Nutanix and changed credentials check 17 | #> 18 | 19 | $ScriptStart = Get-Date 20 | 21 | # RunAs Admin 22 | function Use-RunAs 23 | { 24 | # Check if script is running as Administrator and if not elevate it 25 | # Use Check Switch to check if admin 26 | 27 | param([Switch]$Check) 28 | 29 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 30 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 31 | 32 | IF ($Check) { return $IsAdmin } 33 | 34 | IF ($MyInvocation.ScriptName -ne "") 35 | { 36 | IF (-not $IsAdmin) 37 | { 38 | try 39 | { 40 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 41 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 42 | } 43 | catch 44 | { 45 | Write-Warning "Error - Failed to restart script elevated" 46 | BREAK 47 | } 48 | exit 49 | } 50 | } 51 | } 52 | 53 | Use-RunAs 54 | 55 | IF ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 56 | try { 57 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 58 | } 59 | catch { 60 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 61 | } 62 | 63 | # Get PVS Site 64 | $SiteName = (Get-PvsSite).SiteName 65 | 66 | # Get PVS device in maintenance mode for the selected vDisk 67 | $MaintDeviceNameWindows = (Get-PvsDeviceInfo -SiteName $SiteName | where-Object {$_.Type -eq 2 -and $_.DiskLocatorName -like "*$StoreName\$vDiskName*"}).Name 68 | $MaintDeviceName = (Get-PvsDeviceInfo -SiteName $SiteName | where-Object {$_.Type -eq 2 -and $_.DiskLocatorName -like "*$vDiskName*"}).Name 69 | $vDisks = (Get-PvsDeviceInfo -DeviceName $MaintDeviceName).DiskLocatorName 70 | $vDisks = $vDisks.Split(",").Trim() 71 | 72 | # Variables 73 | $RootFolder = Split-Path -Path $PSScriptRoot 74 | $Date = Get-Date -UFormat "%d.%m.%Y" 75 | $StartMasterLog = "$RootFolder\Logs\Start-Master-$MaintDeviceName.log" 76 | $HypervisorConfig = Import-Clixml "$RootFolder\Hypervisor\Hypervisor.xml" 77 | $Hypervisor = $HypervisorConfig.Hypervisor 78 | $PVSConfig = Import-Clixml "$RootFolder\PVS\PVS.xml" 79 | 80 | # Start logging 81 | Start-Transcript $StartMasterLog | Out-Null 82 | 83 | # Check if more than one vDisk is attached 84 | $SkipBootMenu = $PVSConfig.SkipBootMenu 85 | IF ($vDisks.Count -gt 1) { 86 | Write-Host -ForegroundColor Red "Attention! $MaintDeviceName has more than one vDisks attached! Check if $MaintDeviceName is able to boot!"`n 87 | IF ($SkipBootMenu -eq 'Yes') { 88 | IF (!("$StoreName\$vDiskName" -contains $vDisks[0])) { 89 | Write-Host -ForegroundColor Red "Error, you selected vDisk $StoreName\$vDiskName but '$MaintDeviceName' will boot vDisk"$vDisks[0]"!"`n 90 | IF (-not(Test-Path variable:Task) -or $Task -eq $false) { 91 | Read-Host "Press any key to exit" 92 | } 93 | BREAK 94 | } 95 | } 96 | } 97 | 98 | # Citrix XenServer 99 | IF ($Hypervisor -eq "Xen") { 100 | # Check XenServer PS Module 101 | IF (!(Get-Module -ListAvailable -Name XenServerPSModule)) { 102 | Write-Host -ForegroundColor Red "No XenServer Powershell module found, aborting! Please copy module to 'C:\Program Files\WindowsPowerShell\Modules'" 103 | Read-Host "Press any key to exit" 104 | BREAK 105 | } 106 | Import-Module XenServerPSModule | Out-Null 107 | $Xen = $HypervisorConfig.Host 108 | $Credential = Import-CliXml -Path "$RootFolder\Hypervisor\Credentials-$env:username-Xen.xml" 109 | Try { 110 | Connect-XenServer -url https://$Xen -Creds $Credential -NoWarnNewCertificates -SetDefaultSession | Out-Null 111 | } 112 | Catch { 113 | Write-Warning "Error: $_." 114 | Write-Host -ForegroundColor Red "Unable to connect to configured XenServer '$Xen', check your configuration!" 115 | Read-Host 116 | BREAK 117 | } 118 | IF (-not(Get-XenVM | Where-Object {$_.name_label -eq "$MaintDeviceName"})) { 119 | $MaintDeviceName = $PVSConfig.MaintDeviceName 120 | } 121 | IF (Get-XenVM | Where-Object {$_.name_label -eq "$MaintDeviceName" -and $_.power_state -eq "Halted" -and $_.is_a_template -eq $False}) { 122 | Do { 123 | Write-Host `n 124 | Write-Output "Starting VM '$MaintDeviceName'" 125 | Invoke-XenVM -Name "$MaintDeviceName" -XenAction Start | Out-Null 126 | } Until (Get-XenVM | Where-Object {$_.name_label -eq "$MaintDeviceName" -and $_.power_state -eq "Running"}) 127 | Write-Host `n 128 | Write-Output "'$MaintDeviceName' successfully powered on" 129 | } 130 | } 131 | 132 | # VMWare vSphere 133 | IF ($Hypervisor -eq "ESX") { 134 | # Check VMWare PS Module 135 | IF (!(Get-Module -ListAvailable -Name VMware.PowerCLI)) { 136 | Write-Host -ForegroundColor Red "No VMWare Powershell module found, aborting! Please install module to 'C:\Program Files\WindowsPowerShell\Modules'" 137 | Read-Host "Press any key to exit" 138 | BREAK 139 | } 140 | $ESX = $HypervisorConfig.Host 141 | $Credential = Import-CliXml -Path "$RootFolder\Hypervisor\Credentials-$env:username-ESX.xml" 142 | Try { 143 | Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP $false -Confirm:$false | Out-Null 144 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -confirm:$false | Out-Null 145 | Connect-VIServer -server $ESX -Credential $Credential 146 | } 147 | Catch { 148 | Write-Warning "Error: $_." 149 | Write-Host -ForegroundColor Red "Unable to connect to configured XenServer '$ESX', check your configuration!" 150 | Read-Host 151 | BREAK 152 | } 153 | IF (-not(Get-VM | Where-Object {$_.Name -eq "$MaintDeviceName"})) { 154 | $MaintDeviceName = $PVSConfig.MaintDeviceName 155 | } 156 | IF (Get-VM -Name "$MaintDeviceName" | Where-Object {$_.PowerState -eq "PoweredOff"}) { 157 | Do { 158 | Write-Host `n 159 | Write-Output "Starting VM '$MaintDeviceName'" 160 | Start-VM -VM "$MaintDeviceName" | Out-Null 161 | } Until (Get-VM | Where-Object {$_.Name -eq "$MaintDeviceName" -and $_.PowerState -eq "PoweredOn"}) 162 | Write-Host `n 163 | Write-Output "'$MaintDeviceName' successfully powered on" 164 | } 165 | 166 | } 167 | 168 | # Nutanix AHV 169 | IF ($Hypervisor -eq "AHV") { 170 | # Check Nutanix PS Module 171 | IF ($PSVersionTable.PSVersion -lt "7.0") { 172 | Write-Host -ForegroundColor Red "You need Powershell 7.0 or higher to use the Nutanix Powershell module, please install the recent version of Powershell" 173 | Read-Host "Press any key to exit" 174 | BREAK 175 | } 176 | IF (!(Get-Module -ListAvailable -Name Nutanix.Cli)) { 177 | Write-Host -ForegroundColor Red "No Nutanix Powershell module found, aborting! Please install module to 'C:\Program Files\WindowsPowerShell\Modules'" 178 | Read-Host 179 | BREAK 180 | } 181 | Import-Module Nutanix.Prism.PS.Cmds -Prefix NTNX 182 | $AHV = $HypervisorConfig.Host 183 | $AHVAdmin = Get-Content "$RootFolder\Hypervisor\Admin-AHV.txt" 184 | $AHVPassword = Get-Content "$RootFolder\Hypervisor\Password-AHV.txt" 185 | 186 | Try { 187 | Connect-NutanixCluster -Server $AHV -UserName $AHVAdmin -Password $AHVPassword -AcceptInvalidSSLCerts 188 | IF (-not(Get-NTNXVirtualMachine | Where-Object {$_.Name -eq "$MaintDeviceName"})) { 189 | $MaintDeviceName = "$PVSConfig.MaintDeviceName" 190 | } 191 | $UUID = (Get-NTNXVirtualMachine -Name "$MaintDeviceName").Uuid 192 | IF (Get-NTNXVirtualMachine -Name "$MaintDeviceName" | Where-Object {$_.PowerState -eq "OFF"}) { 193 | Do { 194 | Write-Host `n 195 | Write-Output "Starting VM '$MaintDeviceName'" 196 | Start-NTNXVM -Uuid $UUID | Out-Null 197 | } Until (Get-NTNXVirtualMachine | Where-Object {$_.Name -eq "$MaintDeviceName" -and $_.PowerState -eq "ON"}) 198 | Write-Host `n 199 | Write-Output "'$MaintDeviceName' successfully powered on" 200 | } 201 | } 202 | Catch { 203 | Write-Warning "Error: $_." 204 | Write-Host -ForegroundColor Red "Unable to connect to configured XenServer '$AHV', check your configuration!" 205 | Read-Host 206 | BREAK 207 | } 208 | } 209 | 210 | # Wait until VM is up 211 | $connectiontimeout = 0 212 | Do { 213 | Write-Host `n 214 | Write-Host "Waiting for '$MaintDeviceNameWindows' to boot..." `n 215 | Start-Sleep 8 216 | $connectiontimeout++ 217 | } until (Test-NetConnection "$MaintDeviceNameWindows.$ENV:USERDNSDOMAIN" -Port 5985 | Where-Object {$_.TcpTestSucceeded -or $connectiontimeout -ge 10}) 218 | IF ($connectiontimeout -eq 15) { 219 | Write-Host -ForegroundColor Red "Something is wrong, server not reachable, check the status of $MaintDeviceNameWindows, hit any key to exit" 220 | # Stop Logging 221 | $ScriptEnd = Get-Date 222 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 223 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 224 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" `n 225 | Stop-Transcript #| Out-Null 226 | $Content = Get-Content -Path $StartMasterLog | Select-Object -Skip 18 227 | Set-Content -Value $Content -Path $StartMasterLog 228 | Rename-Item -Path $StartMasterLog -NewName "Start-Master-VM-$MaintDeviceNameWindows-$Date.log" 229 | Read-Host 230 | BREAK 231 | } 232 | else { 233 | Start-Sleep -seconds 15 234 | Write-Host -ForegroundColor Green "Server '$MaintDeviceNameWindows' finished booting" `n 235 | } 236 | 237 | IF (!($WindowsUpdates -or $Evergreen)) { 238 | # Connect to master? 239 | $title = "" 240 | $message = "Do you want to connect to the master VM via RDP?" 241 | $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" 242 | $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" 243 | $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) 244 | $choice=$host.ui.PromptForChoice($title, $message, $options, 0) 245 | 246 | switch ($choice) { 247 | 0 { 248 | $answer = 'Yes' 249 | } 250 | 1 { 251 | $answer = 'No' 252 | } 253 | } 254 | 255 | if ($answer -eq 'Yes') { 256 | $connectiontimeout = 0 257 | Do { 258 | Write-Host `n 259 | Write-Host "Check if '$MaintDeviceNameWindows' is ready to connect..." `n 260 | Start-Sleep 5 261 | $connectiontimeout++ 262 | } until (Test-NetConnection "$MaintDeviceNameWindows.$ENV:USERDNSDOMAIN" -Port 3389 | Where-Object {$_.TcpTestSucceeded -or $connectiontimeout -ge 5}) 263 | start-process mstsc.exe -ArgumentList "/f /admin /v:$MaintDeviceNameWindows" 264 | IF ($connectiontimeout -eq 10) { 265 | Write-Host -ForegroundColor Red "Something is wrong, server not reachable, check the status of $MaintDeviceNameWindows" 266 | } 267 | } 268 | } 269 | 270 | # Stop Logging 271 | $ScriptEnd = Get-Date 272 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 273 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 274 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" `n 275 | Stop-Transcript #| Out-Null 276 | $Content = Get-Content -Path $StartMasterLog | Select-Object -Skip 18 277 | Set-Content -Value $Content -Path $StartMasterLog 278 | Rename-Item -Path $StartMasterLog -NewName "Start-Master-VM-$MaintDeviceNameWindows-$Date.log" -Force -EA SilentlyContinue 279 | 280 | # Install Windows Updates 281 | IF ($WindowsUpdates -eq "True") { 282 | ."$PSScriptRoot\Windows Updates.ps1" 283 | } 284 | 285 | # Launch Evergreen 286 | IF ($Evergreen -eq "True") { 287 | ."$PSScriptRoot\Evergreen.ps1" 288 | } 289 | -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Shrink/Shrink PVS vDisk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will defrag and shrink the latest merged base PVS vDisk. 4 | https://www.citrix.com/blogs/2015/01/19/size-matters-pvs-ram-cache-overflow-sizing/?_ga=1.24764090.1091830672.1452712354 5 | 6 | .DESCRIPTION 7 | The script will first find out what the latest merged base disk is (VHDX). After that the vDisk gets defragmented and shrinked. 8 | At the end you will see the vDisk size before and after shrinking. 9 | vDisk can't be in use while executing the script! 10 | 11 | .EXAMPLE 12 | ."Shrink PVS vDisk.ps1" 13 | 14 | .NOTES 15 | Run as administrator after you create a new merged base disk that isn't in use yet. 16 | Tested with UEFI partitions and standard partititions without system reserved partition. 17 | Sometimes the "detach disk" command from diskpart doesn't work as expected, so the vDisk is still mounted, so the dismount command runs again 18 | after diskpart. 19 | If you want to change the root folder you have to modify the shortcut. 20 | 21 | 22 | Version: 1.1 23 | Author: Dennis Mohrmann <@mohrpheus78> 24 | Creation Date: 2021-10-16 25 | Purpose/Change: 26 | 2021-01-19 Inital version 27 | 2021-10-28 no parameter needed anymore 28 | #> 29 | 30 | $ScriptStart = Get-Date 31 | 32 | # RunAs Admin 33 | function Use-RunAs 34 | { 35 | # Check if script is running as Administrator and if not elevate it 36 | # Use Check Switch to check if admin 37 | 38 | param([Switch]$Check) 39 | 40 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 41 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 42 | 43 | if ($Check) { return $IsAdmin } 44 | 45 | if ($MyInvocation.ScriptName -ne "") 46 | { 47 | if (-not $IsAdmin) 48 | { 49 | try 50 | { 51 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 52 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 53 | } 54 | catch 55 | { 56 | Write-Warning "Error - Failed to restart script elevated" 57 | break 58 | } 59 | exit 60 | } 61 | } 62 | } 63 | 64 | Use-RunAs 65 | 66 | # Variables 67 | $RootFolder = Split-Path -Path $PSScriptRoot 68 | $Date = Get-Date -UFormat "%d.%m.%Y" 69 | $Log = "$RootFolder\Logs\Shrink PVS vDisk.log" 70 | 71 | # Start logging 72 | Start-Transcript $Log | Out-Null 73 | 74 | # FUNCTION Get next free drive letter 75 | # ======================================================================================================================================== 76 | function Get-NextFreeDriveLetter 77 | { 78 | [CmdletBinding()] 79 | param 80 | ( 81 | [string[]]$ExcludeDriveLetter = ('A-F', 'Z'), # Drives to exclude 82 | [switch]$Random, 83 | [switch]$All 84 | ) 85 | 86 | $Drives = Get-ChildItem -Path Function:[a-z]: -Name 87 | 88 | if ($ExcludeDriveLetter) 89 | { 90 | $Drives = $Drives -notmatch "[$($ExcludeDriveLetter -join ',')]" 91 | } 92 | 93 | if ($Random) 94 | { 95 | $Drives = $Drives | Get-Random -Count $Drives.Count 96 | } 97 | 98 | if (-not($All)) 99 | { 100 | foreach ($Drive in $Drives) 101 | { 102 | if (-not(Test-Path -Path $Drive)) 103 | { 104 | return $Drive 105 | } 106 | } 107 | } 108 | else 109 | { 110 | Write-Host $Drives | Where-Object {-not(Test-Path -Path $_)} 111 | } 112 | } 113 | # ======================================================================================================================================== 114 | 115 | 116 | # FUNCTION Convert number to human readable format 117 | # ======================================================================================================================================== 118 | function DisplayInBytes($num) 119 | { 120 | $suffix = "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" 121 | $index = 0 122 | while ($num -gt 1kb) 123 | { 124 | $num = $num / 1kb 125 | $index++ 126 | } 127 | 128 | "{0:N1} {1}" -f $num, $suffix[$index] 129 | } 130 | # ======================================================================================================================================== 131 | 132 | 133 | # FUNCTION Mount VHDX 134 | # ======================================================================================================================================== 135 | function vhdmount($v) 136 | { 137 | try 138 | { 139 | $VHDNumber = Mount-DiskImage -ImagePath "$vdiskpath\$vhd" -NoDriveLetter -Passthru -ErrorAction Stop | Get-DiskImage 140 | $partition = (Get-Partition -DiskNumber $VHDNumber.Number | Where-Object {$_.Type -eq "Basic" -or $_.Type -eq "IFS"}) 141 | Set-Partition -PartitionNumber $partition.PartitionNumber -DiskNumber $VHDNumber.Number -NewDriveLetter $FreeDriveLetter 142 | return "0" 143 | } catch 144 | { 145 | return "1" 146 | } 147 | } 148 | # ======================================================================================================================================== 149 | 150 | 151 | # FUNCTION Dismount VHDX 152 | # ======================================================================================================================================== 153 | function vhddismount($v) 154 | { 155 | try 156 | { 157 | Dismount-DiskImage -ImagePath "$vdiskpath\$vhd" -ErrorAction stop 158 | return "0" 159 | } catch 160 | { 161 | return "1" 162 | } 163 | } 164 | # ======================================================================================================================================== 165 | 166 | 167 | # Scriptblock for defragmenting the PVS vDisk 168 | # ======================================================================================================================================== 169 | # Check if PVS SnapIn is available 170 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 171 | try { 172 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 173 | } 174 | catch { 175 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 176 | } 177 | 178 | Write-Host -ForegroundColor Yellow "Shrink PVS vDisk" `n 179 | 180 | # Get PVS SiteName 181 | $SiteName = (Get-PvsSite).SiteName 182 | 183 | # Get all vDisks 184 | $AllvDisks = Get-PvsDiskInfo -SiteName $SiteName 185 | 186 | # Add property "ID" to object 187 | $ID = 1 188 | $AllvDisks | ForEach-Object { 189 | $_ | Add-Member -MemberType NoteProperty -Name "ID" -Value $ID 190 | $ID += 1 191 | } 192 | 193 | # Show menu to select vDisk 194 | Write-Host "Available vDisks:" `n 195 | $ValidChoices = 1..($AllvDisks.Count) 196 | $Menu = $AllvDisks | ForEach-Object {(($_.ID).toString() + "." + " " + $_.Name + " " + "-" + " " + "Storename:" + " " + $_.Storename)} 197 | $Menu | Out-Host 198 | Write-Host 199 | $vDisk = Read-Host -Prompt 'Select vDisk to shrink' 200 | 201 | $vDisk = $AllvDisks | Where-Object {$_.ID -eq $vDisk} 202 | if ($vDisk.ID -notin $ValidChoices) { 203 | Write-Host -ForegroundColor Red "Selected vDisk not found, aborting!" 204 | Read-Host "Press any key to exit" 205 | BREAK 206 | } 207 | 208 | $vDiskName = $vDisk.Name 209 | $StoreName = $vDisk.StoreName 210 | 211 | $LatestVersion = (Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName).Version | Select-Object -First 1 212 | $MergedBaseVersion = ((Get-PvsDiskVersion -DiskLocatorName $vDiskName -SiteName $SiteName -StoreName $StoreName) | Where-Object {$_.Type -eq '4' -or '0' -and $_.Access -eq 0} | select-Object -First 1) 213 | IF ($MergedBaseVersion.Version -ne $LatestVersion) { 214 | Write-Host -ForegroundColor Red "No actual merged base version found, you select an older merged base version, aborting!" 215 | Read-Host "Press any key to exit" 216 | BREAK 217 | } 218 | $vhd = $MergedBaseVersion.DiskFileName 219 | $vdiskpath = (Get-PvsStore -StoreName "$StoreName").Path 220 | 221 | # $vhdsizebefore = (Get-ChildItem "$vdiskpath" -Recurse | Where-Object {$_.fullname -like "*.vhdx"} | Sort-Object LastWriteTime | Sort-Object -Descending | Select-Object -First 1 @{n='Size';e={DisplayInBytes $_.length}}).Size 222 | $vhdsizebefore = "{0:N0} MB" -f (((Get-ChildItem "$vdiskpath" -Recurse | Where-Object {$_.fullname -like "*.vhdx"} | Sort-Object LastWriteTime | Sort-Object -Descending | Select-Object -First 1) | measure Length -s).Sum /1MB) 223 | 224 | # Get next free drive 225 | $FreeDrive = Get-NextFreeDriveLetter 226 | $FreeDriveLetter = $FreeDrive -replace ".$" # cut ":" 227 | 228 | # Mounting vDisk 229 | $mount = vhdmount -v $vhd 230 | if ($mount -eq "1") 231 | { 232 | Write-Host "Mounting vDisk: $vhd failed" 233 | Read-Host "Press any key to exit" 234 | BREAK 235 | } 236 | Write-Host `n"Mounting vDisk: $vhd"`n 237 | 238 | # Defrag 239 | Write-Host "Running defrag on vDisk: $vhd"`n 240 | Start-Sleep 3 241 | Start-Process "defrag.exe" -ArgumentList "$FreeDrive /X /G /H /U /V" -wait 242 | Start-Sleep 3 243 | 244 | # Sdelete 245 | Write-Host "Running sdelete on vDisk: $vhd"`n 246 | Start-Process "$PSScriptRoot\sdelete64.exe" -ArgumentList "-z -c $FreeDrive" -wait 247 | Start-Sleep 3 248 | 249 | # Dismounting vDisk 250 | $dismount = vhddismount -v $vhd 251 | if ($dismount -eq "1") 252 | { 253 | Write-Host "Failed to dismount vDisk: $vhd" 254 | Read-Host "Press any key to exit" 255 | BREAK 256 | } 257 | Write-Host "Dismounting vDisk: $vhd"`n 258 | Write-Host "Defrag of vDisk: $vhd finished"`n 259 | 260 | # ======================================================================================================================================== 261 | 262 | 263 | # Scriptblock for shrinking the PVS vDisk 264 | # ======================================================================================================================================== 265 | # Generate tempfile for diskpart commands 266 | $tempfile = ($env:TEMP + "\diskpart.txt") 267 | 268 | # Delete temp diskpart file if exists 269 | Write-Host "Delete temp diskpart file if exists"`n 270 | remove-item $tempfile -ea silentlycontinue 271 | 272 | # Generate Diskpart commands and create file 273 | Write-Host "Generate Diskpart commands and creating file"`n 274 | Add-Content $tempfile ("select vdisk file=" + '"' + "$vdiskpath\$vhd" + '"') 275 | Add-Content $tempfile "attach vdisk readonly" 276 | Add-Content $tempfile "compact vdisk" 277 | Add-Content $tempfile "detach vdisk" 278 | Add-Content $tempfile "exit" 279 | 280 | # Generate diskpart command 281 | $diskpartcommand = ("diskpart.exe /s " + $tempfile) 282 | # Execute diskpart 283 | Write-Host "Shrinking vDisk: $vhd"`n 284 | $diskpartcommand | cmd.exe 285 | 286 | # Dismounting vDisk after shrinking if diskpart can't detach the vDisk 287 | $dismount = vhddismount -v $vhd 288 | if ($dismount -eq "1") 289 | { 290 | Write-Host "Failed to dismount vDisk: $vhd" 291 | Read-Host "Press any key to exit" 292 | BREAK 293 | } 294 | Write-Host "Dismounting vDisk: $vhd"`n 295 | 296 | 297 | # Compare PVS vDisk size 298 | # $vhdsizeafter = (Get-ChildItem "$vdiskpath" -Recurse | Where-Object {$_.fullname -like "*.vhdx"} | Sort-Object LastWriteTime | Sort-Object -Descending | Select-Object -First 1 @{n='Size';e={DisplayInBytes $_.length}}).Size 299 | $vhdsizeafter = "{0:N0} MB" -f (((Get-ChildItem "$vdiskpath" -Recurse | Where-Object {$_.fullname -like "*.vhdx"} | Sort-Object LastWriteTime | Sort-Object -Descending | Select-Object -First 1) | measure Length -s).Sum /1MB) 300 | Write-Host "Size of vDisk: $vhd before shrinking: $vhdsizebefore - Size of vDisk: $vhd after shrinking: $vhdsizeafter"`n 301 | # ======================================================================================================================================== 302 | 303 | Write-Host -ForegroundColor Green "Ready! vDisk $vDiskName successfully shrinked, check logfile $log" `n 304 | 305 | $ScriptEnd = Get-Date 306 | $ScriptRuntime = $ScriptEnd - $ScriptStart | Select-Object TotalSeconds 307 | $ScriptRuntimeInSeconds = $ScriptRuntime.TotalSeconds 308 | Write-Host -ForegroundColor Yellow "Script was running for $ScriptRuntimeInSeconds seconds" 309 | 310 | # Stop Logging 311 | Stop-Transcript | Out-Null 312 | $Content = Get-Content -Path $Log | Select-Object -Skip 18 313 | Set-Content -Value $Content -Path $Log 314 | Rename-Item -Path $Log -NewName "$Shrink PVS vDisk-$vDiskName-$Date.log" -EA SilentlyContinue 315 | 316 | Read-Host `n "Press any key to exit" -------------------------------------------------------------------------------- /BGInfo/BGInfo.ps1: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************************* 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # BGInfo powered by Powershell 4 | # 05/12/19 DM Initial release 5 | # 06/12/19 DM Added FSLogix 6 | # 09/12/19 DM Added deviceTRUST 7 | # 11/12/19 DM Initial public release 8 | # 11/12/19 DM Changed method to get session id 9 | # 18/06/20 DM Added MTU Size, WEM and VDA Agent version 10 | # 26/06/20 DM Added FSLogix Version 11 | # 26/06/20 DM Changed BGInfo process handling 12 | # 20/10/20 DM Added percent for FSL 13 | # 21/10/20 DM Added WEM Cache date 14 | # 09/11/20 DM Added Regkeys for IP and DNS (Standard method didn't work wirh Citrix Hypervisor) 15 | # 18/12/20 DM Added GPU Infos and Citrix Rendezvous protocol 16 | # 08/03/21 DM Fixed FriendlyName to FileSystemLabel 17 | # 06/19/23 DM Added Proxy for Rendezvous and user logon time 18 | # ******************************************************************************************************* 19 | 20 | 21 | <# 22 | .SYNOPSIS 23 | Shows information about the user Citrix environment as BGInfo taskbar icon 24 | 25 | 26 | .Description 27 | Execute as logon script or WEM external task to show useful informations about the user environment 28 | 29 | 30 | .EXAMPLE 31 | WEM external task: 32 | Path: powershell.exe 33 | Arguments: -executionpolicy bypass -file "C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo\BGInfo-Taskbar-Taskbar.ps1" 34 | 35 | 36 | .NOTES 37 | Execute as WEM external task (also after reconnect to refresh the information), logonscript or task at logon 38 | Edit the $BGInfoDir (Directory with BGInfo.exe) and $BGInfoFile (BGI file to load) 39 | #> 40 | 41 | # ******************* 42 | # Scripts starts here 43 | # ******************* 44 | 45 | # Source directory for BGInfo/BGInfo File (customize) 46 | $BGInfoDir = 'C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo' 47 | $BGInfoFile = 'Citrix.bgi' 48 | 49 | # Regkey for setting the values (BGinfo gets informations from this source, don't edit!) 50 | $RegistryPath = "HKCU:\BGInfo" 51 | New-Item -Path $RegistryPath -EA SilentlyContinue 52 | 53 | 54 | # ******************** 55 | # General Informations 56 | # ******************** 57 | $IPAddress = (Get-NetIPConfiguration | Where-Object {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.status -ne "Disconnected"}).IPv4Address.IPAddress 58 | New-ItemProperty -Path $RegistryPath -Name "IPAddress" -Value $IPAddress -Force 59 | $DNSServer = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIPGateway -ne $null}).DNSServerSearchOrder 60 | New-ItemProperty -Path $RegistryPath -Name "DNSServer" -Value $DNSServer -Force 61 | 62 | 63 | # *************************** 64 | # Informations about Citrix # 65 | # *************************** 66 | 67 | # Citrix SessionID 68 | $CitrixSessionID = Get-ChildItem -Path "HKCU:\Volatile Environment" -Name 69 | New-ItemProperty -Path $RegistryPath -Name "SessionID" -Value $CitrixSessionID -Force 70 | 71 | # Logon time 72 | $UserLogonTime = (Get-EventLog -LogName 'Application' -Source 'Citrix Desktop Service' -Newest 1 | Where EventID -EQ 1027).TimeWritten 73 | New-ItemProperty -Path $RegistryPath -Name "LogonTime" -Value $UserLogonTime -Force 74 | 75 | # Citrix Clientname 76 | $CitrixClientName = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Name 77 | New-ItemProperty -Path $RegistryPath -Name "Clientname" -Value $CitrixClientName -Force 78 | 79 | # Citrix Client 80 | $CitrixClientVer = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Version 81 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client Ver" -Value $CitrixClientVer -Force 82 | 83 | # Citrix Client Platform 84 | $ClientProductId=(Get-ItemProperty HKLM:\Software\Citrix\ICA\Session\$CitrixSessionID\Connection -name ClientProductId).ClientproductId 85 | if ($ClientProductId -eq 1) {$Platform="Windows"} 86 | if ($ClientProductId -eq 81) {$Platform="Linux"} 87 | if ($ClientProductId -eq 82) {$Platform="Mac"} 88 | if ($ClientProductId -eq 257) {$Platform="HTML5"} 89 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client Platform" -Value $Platform -Force 90 | 91 | # Citrix Client IP 92 | $CitrixClientIP = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Address 93 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client IP" -Value $CitrixClientIP -Force 94 | 95 | # HDX Protocol 96 | $HDXProtocol = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Network_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Protocol 97 | New-ItemProperty -Path $RegistryPath -Name "HDX Protocol" -Value $HDXProtocol -Force 98 | 99 | # HDX Video Codec 100 | $HDXCodec = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_VideoCodecUse 101 | New-ItemProperty -Path $RegistryPath -Name "HDX Codec" -Value $HDXCodec -Force 102 | 103 | # HDX Video Codec Type 104 | $HDXCodecType = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Monitor_VideoCodecType 105 | IF ($HDXCodecType -eq "NotApplicable") {$HDXCodecType = "Inactive"} 106 | New-ItemProperty -Path $RegistryPath -Name "HDX Codec Type" -Value $HDXCodecType -Force 107 | 108 | # HDX Visual Quality 109 | $VisualQuality = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Policy_VisualQuality 110 | New-ItemProperty -Path $RegistryPath -Name "HDX Visual Quality" -Value $VisualQuality -Force 111 | 112 | # HDX Visual Lossless Compression 113 | $VisualLosslessCompression = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Policy_AllowVisuallyLosslessCompression 114 | New-ItemProperty -Path $RegistryPath -Name "HDX Visual Lossless Compression" -Value $VisualLosslessCompression -Force 115 | 116 | # HDX Colorspace 117 | $HDXColorspace = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_VideoCodecColorspace 118 | New-ItemProperty -Path $RegistryPath -Name "HDX Colorspace" -Value $HDXColorspace -Force 119 | 120 | <# 121 | # HDX Web Camera 122 | $HDXWebCamera = Get-ItemProperty -Path "HKCU:\SOFTWARE\Citrix\HdxRealTime\" 123 | $HDXWebCamera = Get-ItemProperty -Path "HKCU:\SOFTWARE\Citrix\HdxRealTime\" 124 | $HDXWebCamera = $HDXWebCamera.'Filter Name' 125 | $HDXWebCamera = $HDXWebCamera -replace '@.*$' 126 | New-ItemProperty -Path $RegistryPath -Name "HDX Web Camera" -Value $HDXWebCamera -Force 127 | #> 128 | 129 | # MTU 130 | $MTUSize = (ctxsession -v | findstr "EDT MTU:" | Select-Object -Last 1).split(":")[1].trimstart() 131 | New-ItemProperty -Path $RegistryPath -Name "MTU Size" -Value $MTUSize -Force 132 | 133 | # Rendezvous 134 | $Rendezvous = ((ctxsession -v | findstr "Rendezvous") | Select-Object -Last 1).split(":")[1].trimstart() 135 | New-ItemProperty -Path $RegistryPath -Name "Rendezvous" -Value $Rendezvous -Force 136 | 137 | # Proxy 138 | $Proxytransport = ((ctxsession -v | findstr "Transport") | Select-Object -Last 1).split(":")[1].trimstart() 139 | if ($Proxytransport -like "*PROXY*") { 140 | $Proxy = "YES" 141 | } 142 | else { 143 | $Proxy ="No" 144 | } 145 | New-ItemProperty -Path $RegistryPath -Name "Proxy" -Value $Proxy -Force 146 | 147 | # WEM Version 148 | $WEM = (Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -like "*Citrix Workspace Environment*"}).DisplayVersion | Select-Object -First 1 149 | New-ItemProperty -Path $RegistryPath -Name "WEM Version" -Value $WEM -Force 150 | 151 | # WEM Agent logon 152 | $WEMAgentLastRun = Get-EventLog -LogName 'WEM Agent Service' -Message '*Starting Logon Processing for User*' -Newest 1 |Select-Object -ExpandProperty TimeGenerated 153 | New-ItemProperty -Path $RegistryPath -Name "WEMAgentLastRun" -Value $WEMAgentLastRun -Force 154 | 155 | # WEM Cache 156 | $WEMCache = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Norskale\Agent Host").AgentCacheAlternateLocation 157 | IF ($WEMCache -eq "") 158 | { 159 | $WEMCache = "${ENV:ProgramFiles(x86)}\Citrix\Workspace Environment Management Agent\Local Databases" 160 | } 161 | $WEMCacheModified = (Get-Item "$WEMCache\LocalAgentCache.db").LastWriteTime.ToString("MM'/'dd'/'yyyy HH:mm:ss") 162 | New-ItemProperty -Path $RegistryPath -Name "WEMCacheModified" -Value $WEMCacheModified -Force 163 | 164 | 165 | # **************************** 166 | # Informations about FSLogix # 167 | # **************************** 168 | 169 | # Profilesize 170 | $ProfileSize = "{0:N2} GB" -f ((Get-ChildItem $ENV:USERPROFILE -Force -Recurse -EA SilentlyContinue | Measure-Object Length -s).Sum /1GB) 171 | New-ItemProperty -Path $RegistryPath -Name "Profile Size" -Value $ProfileSize -Force 172 | 173 | # FSLogix Profile Status 174 | $FSLProfileStatus = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | Select-Object -ExpandProperty HealthStatus 175 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Status" -Value $FSLProfileStatus -Force 176 | 177 | # FSLogix Profile Size 178 | $FSLProfileSize = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.Size / 1GB)} 179 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size" -Value $FSLProfileSize -Force 180 | 181 | # FSLogix Profile Size Remaining 182 | $FSLProfileSizeRemaining = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.SizeRemaining / 1GB)} 183 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size Remaining" -Value $FSLProfileSizeRemaining -Force 184 | 185 | # FSLogix Profile size percent 186 | $FSLProfileSize = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} 187 | $FSLProfilePercentFree = [Math]::round((($FSLProfileSize.SizeRemaining/$FSLProfileSize.size) * 100)) 188 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size percent" -Value $FSLProfilePercentFree -Force 189 | 190 | # FSLogix O365 Status 191 | $FSLO365Status = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | Select-Object -ExpandProperty HealthStatus 192 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Status" -Value $FSLO365Status -Force 193 | 194 | # FSLogix O365 Size 195 | $FSLO365Size = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.Size / 1GB)} 196 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size" -Value $FSLO365Size -Force 197 | 198 | 199 | # FSLogix O365 Size Remaining 200 | $FSLO365SizeRemaining = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.SizeRemaining / 1GB)} 201 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size Remaining" -Value $FSLO365SizeRemaining -Force 202 | 203 | # FSLogix O365 size percent 204 | $FSLO365Size = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} 205 | $FSLO365PercentFree = [Math]::round((($FSLO365Size.SizeRemaining/$FSLO365Size.size) * 100)) 206 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size percent" -Value $FSLO365PercentFree -Force 207 | 208 | # FSLogix Version 209 | $FSLVersion = (Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -eq "Microsoft FSLogix Apps"}).DisplayVersion 210 | New-ItemProperty -Path $RegistryPath -Name "FSL Version" -Value $FSLVersion -Force 211 | 212 | 213 | # ************************ 214 | # Informations about GPU # 215 | # ************************ 216 | 217 | # GPU 218 | $GPU = ((Get-WmiObject win32_videocontroller) | Where-Object {$_.Name -notlike "Citrix*"}).Name 219 | New-ItemProperty -Path $RegistryPath -Name "GPU" -Value $GPU -Force 220 | 221 | # Hardware Encoder 222 | $HardwareEncoder = (Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Base | Where-Object {$_.SessionID -eq $CitrixSessionID}).Component_Monitor_HardwareEncodeInUse | Select-Object -First 1 223 | IF ($HardwareEncoder -eq "True") 224 | { 225 | New-ItemProperty -Path $RegistryPath -Name "HW Encoder" -Value Yes -Force 226 | } 227 | ELSE 228 | { 229 | New-ItemProperty -Path $RegistryPath -Name "HW Encoder" -Value No -Force 230 | } 231 | 232 | # HDX 3D 233 | $HDX3D = (Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Base | Where-Object {$_.SessionID -eq $CitrixSessionID}).Component_HDX3DPro | Select-Object -First 1 234 | IF ($HDX3D -eq "True") 235 | { 236 | New-ItemProperty -Path $RegistryPath -Name "HDX3D" -Value Yes -Force 237 | } 238 | ELSE 239 | { 240 | New-ItemProperty -Path $RegistryPath -Name "HDX3D" -Value No -Force 241 | } 242 | 243 | 244 | # BGInfo # 245 | # Start BGInfo 246 | Start-Process -FilePath "$BGInfoDir\Bginfo64.exe" -ArgumentList @('/nolicprompt','/timer:0',"`"$BGInfoDir\$BGInfoFile`"") 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /BGInfo/BGInfo-Taskbar.ps1: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************************* 2 | # D. Mohrmann, S&L Firmengruppe, Twitter: @mohrpheus78 3 | # BGInfo powered by Powershell 4 | 5 | # 05/12/19 DM Initial release 6 | # 06/12/19 DM Added FSLogix 7 | # 09/12/19 DM Added deviceTRUST 8 | # 11/12/19 DM Initial public release 9 | # 11/12/19 DM Changed method to get session id 10 | # 18/06/20 DM Added MTU Size, WEM and VDA Agent version 11 | # 26/06/20 DM Added FSLogix Version 12 | # 26/06/20 DM Changed BGInfo process handling 13 | # 20/10/20 DM Added percent for FSL 14 | # 21/10/20 DM Added WEM Cache date 15 | # 09/11/20 DM Added Regkeys for IP and DNS (Standard method didn't work wirh Citrix Hypervisor) 16 | # 18/12/20 DM Added GPU Infos and Citrix Rendezvous protocol 17 | # 08/03/21 DM Fixed FriendlyName to FileSystemLabel 18 | # 06/19/23 DM Added Proxy for Rendezvous and user logon time 19 | # ******************************************************************************************************* 20 | 21 | 22 | 23 | <# 24 | .SYNOPSIS 25 | Shows information about the user Citrix environment as BGInfo taskbar icon 26 | 27 | 28 | .Description 29 | Execute as logon script or WEM external task to show useful informations about the user environment 30 | 31 | 32 | .EXAMPLE 33 | WEM external task: 34 | Path: powershell.exe 35 | Arguments: -executionpolicy bypass -file "C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo\BGInfo-Taskbar-Taskbar.ps1" 36 | 37 | 38 | .NOTES 39 | Execute as WEM external task (also after reconnect to refresh the information), logonscript or task at logon 40 | Edit the $BGInfoDir (Directory with BGInfo.exe) and $BGInfoFile (BGI file to load) 41 | #> 42 | 43 | 44 | 45 | # ******************* 46 | # Scripts starts here 47 | # ******************* 48 | 49 | # Source directory for BGInfo/BGInfo File (customize) 50 | $BGInfoDir = 'C:\Program Files (x86)\SuL\Citrix Management Tools\BGInfo' 51 | $BGInfoFile = 'Citrix.bgi' 52 | 53 | # Regkey for setting the values (BGinfo gets informations from this source, don't edit!) 54 | $RegistryPath = "HKCU:\BGInfo" 55 | New-Item -Path $RegistryPath -EA SilentlyContinue 56 | 57 | 58 | # ******************** 59 | # General Informations 60 | # ******************** 61 | $IPAddress = (Get-NetIPConfiguration | Where-Object {$_.IPv4DefaultGateway -ne $null -and $_.NetAdapter.status -ne "Disconnected"}).IPv4Address.IPAddress 62 | New-ItemProperty -Path $RegistryPath -Name "IPAddress" -Value $IPAddress -Force 63 | $DNSServer = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIPGateway -ne $null}).DNSServerSearchOrder 64 | New-ItemProperty -Path $RegistryPath -Name "DNSServer" -Value $DNSServer -Force 65 | 66 | 67 | # *************************** 68 | # Informations about Citrix # 69 | # *************************** 70 | 71 | # Citrix SessionID 72 | $CitrixSessionID = Get-ChildItem -Path "HKCU:\Volatile Environment" -Name 73 | New-ItemProperty -Path $RegistryPath -Name "SessionID" -Value $CitrixSessionID -Force 74 | 75 | # Logon time 76 | $UserLogonTime = (Get-EventLog -LogName 'Application' -Source 'Citrix Desktop Service' -Newest 1 | Where EventID -EQ 1027).TimeWritten 77 | New-ItemProperty -Path $RegistryPath -Name "LogonTime" -Value $UserLogonTime -Force 78 | 79 | # Citrix Clientname 80 | $CitrixClientName = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Name 81 | New-ItemProperty -Path $RegistryPath -Name "Clientname" -Value $CitrixClientName -Force 82 | 83 | # Citrix Client 84 | $CitrixClientVer = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Version 85 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client Ver" -Value $CitrixClientVer -Force 86 | 87 | # Citrix Client Platform 88 | $ClientProductId=(Get-ItemProperty HKLM:\Software\Citrix\ICA\Session\$CitrixSessionID\Connection -name ClientProductId).ClientproductId 89 | if ($ClientProductId -eq 1) {$Platform="Windows"} 90 | if ($ClientProductId -eq 81) {$Platform="Linux"} 91 | if ($ClientProductId -eq 82) {$Platform="Mac"} 92 | if ($ClientProductId -eq 257) {$Platform="HTML5"} 93 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client Platform" -Value $Platform -Force 94 | 95 | # Citrix Client IP 96 | $CitrixClientIP = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Client_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Address 97 | New-ItemProperty -Path $RegistryPath -Name "Citrix Client IP" -Value $CitrixClientIP -Force 98 | 99 | # HDX Protocol 100 | $HDXProtocol = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_Network_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Protocol 101 | New-ItemProperty -Path $RegistryPath -Name "HDX Protocol" -Value $HDXProtocol -Force 102 | 103 | # HDX Video Codec 104 | $HDXCodec = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_VideoCodecUse 105 | New-ItemProperty -Path $RegistryPath -Name "HDX Codec" -Value $HDXCodec -Force 106 | 107 | # HDX Video Codec Type 108 | $HDXCodecType = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_Monitor_VideoCodecType 109 | IF ($HDXCodecType -eq "NotApplicable") {$HDXCodecType = "Inactive"} 110 | New-ItemProperty -Path $RegistryPath -Name "HDX Codec Type" -Value $HDXCodecType -Force 111 | 112 | # HDX Visual Quality 113 | $VisualQuality = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Policy_VisualQuality 114 | New-ItemProperty -Path $RegistryPath -Name "HDX Visual Quality" -Value $VisualQuality -Force 115 | 116 | # HDX Visual Lossless Compression 117 | $VisualLosslessCompression = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Policy_AllowVisuallyLosslessCompression 118 | New-ItemProperty -Path $RegistryPath -Name "HDX Visual Lossless Compression" -Value $VisualLosslessCompression -Force 119 | 120 | # HDX Colorspace 121 | $HDXColorspace = Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Enum | Where-Object {$_.SessionID -eq $CitrixSessionID} | Select-Object -ExpandProperty Component_VideoCodecColorspace 122 | New-ItemProperty -Path $RegistryPath -Name "HDX Colorspace" -Value $HDXColorspace -Force 123 | 124 | <# 125 | # HDX Web Camera 126 | $HDXWebCamera = Get-ItemProperty -Path "HKCU:\SOFTWARE\Citrix\HdxRealTime\" 127 | $HDXWebCamera = Get-ItemProperty -Path "HKCU:\SOFTWARE\Citrix\HdxRealTime\" 128 | $HDXWebCamera = $HDXWebCamera.'Filter Name' 129 | $HDXWebCamera = $HDXWebCamera -replace '@.*$' 130 | New-ItemProperty -Path $RegistryPath -Name "HDX Web Camera" -Value $HDXWebCamera -Force 131 | #> 132 | 133 | # MTU 134 | $MTUSize = (ctxsession -v | findstr "EDT MTU:" | Select-Object -Last 1).split(":")[1].trimstart() 135 | New-ItemProperty -Path $RegistryPath -Name "MTU Size" -Value $MTUSize -Force 136 | 137 | # Rendezvous 138 | $Rendezvous = ((ctxsession -v | findstr "Rendezvous") | Select-Object -Last 1).split(":")[1].trimstart() 139 | New-ItemProperty -Path $RegistryPath -Name "Rendezvous" -Value $Rendezvous -Force 140 | 141 | # Proxy 142 | $Proxytransport = ((ctxsession -v | findstr "Transport") | Select-Object -Last 1).split(":")[1].trimstart() 143 | if ($Proxytransport -like "*PROXY*") { 144 | $Proxy = "YES" 145 | } 146 | else { 147 | $Proxy ="No" 148 | } 149 | New-ItemProperty -Path $RegistryPath -Name "Proxy" -Value $Proxy -Force 150 | 151 | # WEM Version 152 | $WEM = (Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -like "*Citrix Workspace Environment*"}).DisplayVersion | Select-Object -First 1 153 | New-ItemProperty -Path $RegistryPath -Name "WEM Version" -Value $WEM -Force 154 | 155 | # WEM Agent logon 156 | $WEMAgentLastRun = Get-EventLog -LogName 'WEM Agent Service' -Message '*Starting Logon Processing for User*' -Newest 1 |Select-Object -ExpandProperty TimeGenerated 157 | New-ItemProperty -Path $RegistryPath -Name "WEMAgentLastRun" -Value $WEMAgentLastRun -Force 158 | 159 | # WEM Cache 160 | $WEMCache = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Norskale\Agent Host").AgentCacheAlternateLocation 161 | IF ($WEMCache -eq "") 162 | { 163 | $WEMCache = "${ENV:ProgramFiles(x86)}\Citrix\Workspace Environment Management Agent\Local Databases" 164 | } 165 | $WEMCacheModified = (Get-Item "$WEMCache\LocalAgentCache.db").LastWriteTime.ToString("MM'/'dd'/'yyyy HH:mm:ss") 166 | New-ItemProperty -Path $RegistryPath -Name "WEMCacheModified" -Value $WEMCacheModified -Force 167 | 168 | 169 | # **************************** 170 | # Informations about FSLogix # 171 | # **************************** 172 | 173 | # Profilesize 174 | $ProfileSize = "{0:N2} GB" -f ((Get-ChildItem $ENV:USERPROFILE -Force -Recurse -EA SilentlyContinue | Measure-Object Length -s).Sum /1GB) 175 | New-ItemProperty -Path $RegistryPath -Name "Profile Size" -Value $ProfileSize -Force 176 | 177 | # FSLogix Profile Status 178 | $FSLProfileStatus = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | Select-Object -ExpandProperty HealthStatus 179 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Status" -Value $FSLProfileStatus -Force 180 | 181 | # FSLogix Profile Size 182 | $FSLProfileSize = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.Size / 1GB)} 183 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size" -Value $FSLProfileSize -Force 184 | 185 | # FSLogix Profile Size Remaining 186 | $FSLProfileSizeRemaining = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.SizeRemaining / 1GB)} 187 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size Remaining" -Value $FSLProfileSizeRemaining -Force 188 | 189 | # FSLogix Profile size percent 190 | $FSLProfileSize = Get-Volume -FileSystemLabel *Profile-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} 191 | $FSLProfilePercentFree = [Math]::round((($FSLProfileSize.SizeRemaining/$FSLProfileSize.size) * 100)) 192 | New-ItemProperty -Path $RegistryPath -Name "FSL Profile Size percent" -Value $FSLProfilePercentFree -Force 193 | 194 | # FSLogix O365 Status 195 | $FSLO365Status = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | Select-Object -ExpandProperty HealthStatus 196 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Status" -Value $FSLO365Status -Force 197 | 198 | # FSLogix O365 Size 199 | $FSLO365Size = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.Size / 1GB)} 200 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size" -Value $FSLO365Size -Force 201 | 202 | 203 | # FSLogix O365 Size Remaining 204 | $FSLO365SizeRemaining = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} | ForEach-Object {[string]::Format("{0:0.00} GB", $_.SizeRemaining / 1GB)} 205 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size Remaining" -Value $FSLO365SizeRemaining -Force 206 | 207 | # FSLogix O365 size percent 208 | $FSLO365Size = Get-Volume -FileSystemLabel *O365-$ENV:USERNAME* | Where-Object { $_.DriveType -eq 'Fixed'} 209 | $FSLO365PercentFree = [Math]::round((($FSLO365Size.SizeRemaining/$FSLO365Size.size) * 100)) 210 | New-ItemProperty -Path $RegistryPath -Name "FSL O365 Size percent" -Value $FSLO365PercentFree -Force 211 | 212 | # FSLogix Version 213 | $FSLVersion = (Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName -eq "Microsoft FSLogix Apps"}).DisplayVersion 214 | New-ItemProperty -Path $RegistryPath -Name "FSL Version" -Value $FSLVersion -Force 215 | 216 | 217 | # ************************ 218 | # Informations about GPU # 219 | # ************************ 220 | 221 | # GPU 222 | $GPU = (Get-WmiObject win32_videocontroller).Name 223 | New-ItemProperty -Path $RegistryPath -Name "GPU" -Value $GPU -Force 224 | 225 | # Hardware Encoder 226 | $HardwareEncoder = (Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Base | Where-Object {$_.SessionID -eq $CitrixSessionID}).Component_Monitor_HardwareEncodeInUse | Select-Object -First 1 227 | IF ($HardwareEncoder -eq "True") 228 | { 229 | New-ItemProperty -Path $RegistryPath -Name "HW Encoder" -Value Yes -Force 230 | } 231 | ELSE 232 | { 233 | New-ItemProperty -Path $RegistryPath -Name "HW Encoder" -Value No -Force 234 | } 235 | 236 | # HDX 3D 237 | $HDX3D = (Get-WmiObject -Namespace root\citrix\hdx -Class Citrix_VirtualChannel_Thinwire_Base | Where-Object {$_.SessionID -eq $CitrixSessionID}).Component_HDX3DPro | Select-Object -First 1 238 | IF ($HDX3D -eq "True") 239 | { 240 | New-ItemProperty -Path $RegistryPath -Name "HDX3D" -Value Yes -Force 241 | } 242 | ELSE 243 | { 244 | New-ItemProperty -Path $RegistryPath -Name "HDX3D" -Value No -Force 245 | } 246 | 247 | # Execute BGInfo as Tray icon, if already executed end process before 248 | $BGInfoID = (Get-Process | Where-Object {$_.ProcessName -eq "BGInfo64" -and $_.SI -eq "$CitrixSessionID"}).Id 249 | Stop-Process -Id $BGInfoID -EA SilentlyContinue 250 | Start-Sleep -Seconds 1 251 | Start-Process -FilePath "$BGInfoDir\Bginfo64.exe" -ArgumentList @('/taskbar','/nolicprompt','/timer:0',"`"$BGInfoDir\$BGInfoFile`"") -------------------------------------------------------------------------------- /PVS Admin Toolkit/vDisk Documentation/PVS vDisk versions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script will generate a HTML report of your current vDisk versions 4 | 5 | .DESCRIPTION 6 | The purpose of the script is, that you have a documentation of your vDisk versions, especially the descriptions of the versions which get lost after merging a vDisk and deleting 7 | the old versions. 8 | 9 | .PARAMETER -outputpath 10 | The path where the report is saved, default is "C:\Program Files (x86)\PVS Admin Toolkit\vDisk Documentation". 11 | 12 | .EXAMPLE 13 | & '.\PVS vDisk versions.ps1' -outputpath C:\Users\admin\Desktop or use shortcut 14 | 15 | .NOTES 16 | The script is based on the excellent PVS Health Check script from Sacha Thomet (@sacha81): https://github.com/sacha81/citrix-pvs-healthcheck/blob/master/Citrix-PVS-Farm-Health-toHTML_Parameters.xml 17 | I used most of the code and added the decription, there is also no need of the XML file. If you want to change the root folder you have to modify the shortcut and the output path for the report. 18 | 19 | Author: Dennis Mohrmann <@mohrpheus78> 20 | Creation Date: 2021-10-16 21 | #> 22 | 23 | [CmdletBinding()] 24 | 25 | param ( 26 | # Path to HTML Report 27 | [Parameter(Mandatory = $false)] 28 | [ValidateNotNull()] 29 | [ValidateNotNullOrEmpty()] 30 | [Array]$outputpath = "C:\Program Files (x86)\PVS Admin Toolkit\vDisk Documentation" 31 | ) 32 | 33 | 34 | # RunAs Admin 35 | function Use-RunAs 36 | { 37 | # Check if script is running as Administrator and if not elevate it 38 | # Use Check Switch to check if admin 39 | 40 | param([Switch]$Check) 41 | 42 | $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 43 | ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 44 | 45 | if ($Check) { return $IsAdmin } 46 | 47 | if ($MyInvocation.ScriptName -ne "") 48 | { 49 | if (-not $IsAdmin) 50 | { 51 | try 52 | { 53 | $arg = "-WindowStyle Maximized -file `"$($MyInvocation.ScriptName)`"" 54 | Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop' 55 | } 56 | catch 57 | { 58 | Write-Warning "Error - Failed to restart script elevated" 59 | break 60 | } 61 | exit 62 | } 63 | } 64 | } 65 | 66 | Use-RunAs 67 | 68 | # Check if PVS SnapIn is available 69 | if ($null -eq (Get-PSSnapin "Citrix.PVS.SnapIn" -EA silentlycontinue)) { 70 | try { 71 | Add-PSSnapin Citrix.PVS.SnapIn -ErrorAction Stop 72 | } 73 | catch { 74 | write-error "Error loading Citrix.PVS.SnapIn PowerShell snapin"; Return } 75 | } 76 | 77 | #$ReportDate = (Get-Date -UFormat "%A, %d. %B %Y %R") 78 | #============================================================================================== 79 | 80 | Write-Host -ForegroundColor Yellow "PVS vDisk version documentation" `n 81 | 82 | $RootFolder = Split-Path -Path $PSScriptRoot 83 | $Date = Get-Date -UFormat "%d.%m.%Y" 84 | $logfile = Join-Path "$RootFolder\Logs" ("PVS vDisk Version-$Date.log") 85 | $resultsHTM = Join-Path $outputpath ("PVS vDisk Versions-$Date.htm") 86 | 87 | #Header for Table 1 "vDisk Checks" 88 | $vDiksFirstheaderName = "vDisk Name" 89 | $vDiskheaderNames = "Site", "Store", "vDiskFileName", "Version", "Type", "CreateDate" , "ReplState", "Description" 90 | $vDiskheaderWidths = "auto","auto","auto","auto","auto","auto","auto","auto" 91 | $vDisktablewidth = "1400" 92 | 93 | #============================================================================================== 94 | #Log Function 95 | function LogMe() { 96 | Param( 97 | [parameter(Mandatory = $true, ValueFromPipeline = $true)] $logEntry, 98 | [switch]$display, 99 | [switch]$err, 100 | [switch]$warning, 101 | [switch]$progress 102 | ) 103 | 104 | if ($err) { 105 | $logEntry = "[ERROR] $logEntry" ; Write-Host "$logEntry" -Foregroundcolor Red} 106 | elseif ($warning) { 107 | Write-Warning "$logEntry" ; $logEntry = "[WARNING] $logEntry"} 108 | elseif ($progress) { 109 | Write-Host "$logEntry" -Foregroundcolor Green} 110 | elseif ($display) { 111 | Write-Host "$logEntry" 112 | } 113 | 114 | #$logEntry = ((Get-Date -uformat "%D %T") + " - " + $logEntry) 115 | $logEntry | Out-File $logFile -Append 116 | } 117 | 118 | #============================================================================================== 119 | Function writeHtmlHeader { 120 | param($title, $fileName) 121 | #$date = $ReportDate 122 | $head = @" 123 | 124 | 125 | 126 | $title 127 | 153 | 154 | 155 | 156 | 157 | 161 | 162 |
158 | 159 | $title 160 |
163 | "@ 164 | $head | Out-File $fileName 165 | } 166 | 167 | # ============================================================================================== 168 | Function writeTableHeader { 169 | param($fileName, $firstheaderName, $headerNames, $headerWidths, $tablewidth) 170 | $tableHeader = @" 171 | 172 | 173 | 174 | "@ 175 | $i = 0 176 | while ($i -lt $headerNames.count) { 177 | $headerName = $headerNames[$i] 178 | $headerWidth = $headerWidths[$i] 179 | $tableHeader += "" 180 | $i++ 181 | } 182 | $tableHeader += "" 183 | $tableHeader | Out-File $fileName -append 184 | } 185 | 186 | #============================================================================================== 187 | Function writeData { 188 | param($data, $fileName, $headerNames) 189 | 190 | $data.Keys | sort | ForEach-Object { 191 | $tableEntry += "" 192 | $computerName = $_ 193 | $tableEntry += ("") 194 | $headerNames | ForEach-Object { 195 | try { 196 | if ($data.$computerName.$_[0] -eq "SUCCESS") { $bgcolor = "#387C44"; $fontColor = "#FFFFFF" } 197 | elseif ($data.$computerName.$_[0] -eq "WARNING") { $bgcolor = "#FF7700"; $fontColor = "#FFFFFF" } 198 | elseif ($data.$computerName.$_[0] -eq "ERROR") { $bgcolor = "#FF0000"; $fontColor = "#FFFFFF" } 199 | else { $bgcolor = "#e6e6e6"; $fontColor = "#313233" } 200 | $testResult = $data.$computerName.$_[1] 201 | } 202 | catch { 203 | $bgcolor = "#e6e6e6"; $fontColor = "#313233" 204 | $testResult = "" 205 | } 206 | 207 | $tableEntry += ("") 208 | } 209 | $tableEntry += "" 210 | } 211 | $tableEntry | Out-File $fileName -append 212 | } 213 | 214 | # =============================================================================================== 215 | function PVSvDiskCheck() { 216 | # ======= PVS vDisk Check #================================================================== 217 | "Check PVS vDisks" | LogMe -display -progress 218 | " " | LogMe -display -progress 219 | 220 | $AllvDisks = Get-PvsDiskInfo -SiteName $Sitename 221 | $global:vdiskResults = @{} 222 | 223 | foreach($vDisk in $AllvDisks ) 224 | { 225 | $VDtests = @{} 226 | 227 | #VdiskName 228 | $vDiskName = $vDisk | %{ $_.Name } 229 | "Name of vDisk: $vDiskName" | LogMe -display -progress 230 | $vDiskName 231 | 232 | #VdiskSite 233 | $VdiskSite = $vDisk | %{ $_.sitename } 234 | "Site: $VdiskSite" | LogMe -display -progress 235 | $VDtests.Site = "NEUTRAL", $VdiskSite 236 | 237 | #VdiskStore 238 | $vDiskStore = $vDisk | %{ $_.StoreName } 239 | "vDiskStore: $vDiskStore" | LogMe -display -progress 240 | $VDtests.Store = "NEUTRAL", $vDiskStore 241 | 242 | #Get details of each version of the vDisk: 243 | $vDiskVersions = Get-PvsDiskVersion -Name $vDiskName -SiteName $VdiskSite -StoreName $vDiskStore 244 | 245 | $vDiskVersionTable = @{} 246 | foreach($diskVersion in $vDiskVersions){ 247 | 248 | #VdiskVersionFilename 249 | $diskversionfilename = $diskVersion | %{ $_.DiskFileName } 250 | "Filename of Version: $diskversionfilename" | LogMe -display -progress 251 | $vDiskVersionTable.diskversionfilename += $diskversionfilename +="
" 252 | 253 | #VdiskVersionVersion 254 | $diskversionVersion = $diskVersion | %{ $_.Version } 255 | $StringDiskversionVersion = $diskversionVersion | Out-String 256 | "Version: $StringDiskversionVersion" | LogMe -display -progress 257 | $vDiskVersionTable.StringDiskversionVersion += $StringDiskversionVersion +="
" 258 | 259 | #VdiskVersionType 260 | $diskversionType = $diskVersion | %{ $_.Type } 261 | $StringDiskversionType = $diskversionType | Out-String 262 | if ($diskversionType -eq 4) {$StringDiskversionType = "Base"} 263 | if ($diskversionType -eq 1) {$StringDiskversionType = "Version"} 264 | "Type: $StringDiskversionType" | LogMe -display -progress 265 | $vDiskVersionTable.DiskversionType += $StringDiskversionType +="
" 266 | 267 | #VdiskVersionCreateDate 268 | $diskversionCreateDate = $diskVersion | %{ $_.CreateDate } 269 | "Create Date: $diskversionCreateDate" | LogMe -display -progress 270 | $vDiskVersionTable.diskversionCreateDate += $diskversionCreateDate +="
" 271 | 272 | #VdiskVersionDescription 273 | $diskversionDescription = $diskVersion | %{ $_.Description } 274 | "Description: $diskversionDescription" | LogMe -display -progress 275 | $vDiskVersionTable.diskversionDescription += $diskversionDescription +="
" 276 | 277 | #VdiskVersion ReplState (GoodInventoryStatus) 278 | $diskversionGoodInventoryStatus = $diskVersion | %{ $_.GoodInventoryStatus } 279 | $StringDiskversionGoodInventoryStatus = $diskversionGoodInventoryStatus | Out-String 280 | "Replication: $StringDiskversionGoodInventoryStatus" | LogMe -display -progress 281 | #Check if correct replicated, count Replication Errors 282 | Write-Host "Replication State: " $DiskversionGoodInventoryStatus 283 | $ReplErrorCount = 0 284 | if($DiskversionGoodInventoryStatus -like "True" ){ 285 | $ReplErrorCount += 0 286 | } else { 287 | $ReplErrorCount += 1} 288 | $vDiskVersionTable.StringDiskversionGoodInventoryStatus += $StringDiskversionGoodInventoryStatus +="
" 289 | #Check if correct replicated THE LAST DISK 290 | if($ReplErrorCount -eq 0 ){ 291 | "$diskversionfilename correct replicated" | LogMe 292 | $ReplStateStatus = "SUCCESS" 293 | } else { 294 | "$diskversionfilename not correct replicated $ReplErrorCount errors" | LogMe -display -err 295 | $ReplStateStatus = "ERROR"} 296 | } 297 | 298 | 299 | 300 | $VDtests.vDiskFileName = "Neutral", $vDiskVersionTable.diskversionfilename 301 | $VDtests.Version = "Neutral", $vDiskVersionTable.StringDiskversionVersion 302 | $VDtests.Type = "Neutral", $vDiskVersionTable.DiskversionType 303 | $VDtests.CreateDate = "Neutral", $vDiskVersionTable.diskversionCreateDate 304 | $VDtests.ReplState = "$ReplStateStatus", $vDiskVersionTable.StringDiskversionGoodInventoryStatus 305 | $VDtests.Description = "Neutral", $vDiskVersionTable.diskversionDescription 306 | 307 | #image name adds Site name in multi site reports 308 | if ($Sitename.count -ne 1) {$global:vdiskResults."$vDiskName ($VdiskSite)" = $VDtests} 309 | else {$global:vdiskResults.$vDiskName = $VDtests} 310 | 311 | } 312 | 313 | 314 | } 315 | 316 | 317 | #============================================================================================== 318 | #HTML function 319 | function WriteHTML() { 320 | 321 | # ======= Write all results to an html file ================================================= 322 | Write-Host ("Saving results to html report: " + $resultsHTM) 323 | writeHtmlHeader "$EnvName" $resultsHTM 324 | writeTableHeader $resultsHTM $vDiksFirstheaderName $vDiskheaderNames $vDiskheaderWidths $vDisktablewidth 325 | $global:vdiskResults | sort-object -property ReplState | % { writeData $vdiskResults $resultsHTM $vDiskheaderNames } 326 | } 327 | 328 | 329 | #============================================================================================== 330 | # == MAIN SCRIPT == 331 | #============================================================================================== 332 | $scriptstart = Get-Date 333 | rm $logfile -force -EA SilentlyContinue 334 | "Begin with Citrix Provisioning vDisk Check" | LogMe -display -progress 335 | " " | LogMe -display -progress 336 | 337 | "Initiate PVS vDisk check" | LogMe 338 | $Sitename = (Get-PvsSite).SiteName 339 | $EnvName = "PVS vDisk Versions" 340 | PVSvDiskCheck 341 | WriteHTML 342 | 343 | $scriptend = Get-Date 344 | $scriptruntime = $scriptend - $scriptstart | Select-Object TotalSeconds 345 | $scriptruntimeInSeconds = $scriptruntime.TotalSeconds 346 | "Script was running for $scriptruntimeInSeconds " | LogMe -display -progress 347 | 348 | .$resultsHTM --------------------------------------------------------------------------------
$firstheaderName$headerName
$computerName$testResult