├── 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 | 
--------------------------------------------------------------------------------
/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 | 
54 | 
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 | 
43 | 
--------------------------------------------------------------------------------
/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 | 
81 | 
82 | 
83 | 
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 | |
158 |
159 | $title
160 | |
161 |
162 |
163 | "@
164 | $head | Out-File $fileName
165 | }
166 |
167 | # ==============================================================================================
168 | Function writeTableHeader {
169 | param($fileName, $firstheaderName, $headerNames, $headerWidths, $tablewidth)
170 | $tableHeader = @"
171 |
172 |
173 | | $firstheaderName |
174 | "@
175 | $i = 0
176 | while ($i -lt $headerNames.count) {
177 | $headerName = $headerNames[$i]
178 | $headerWidth = $headerWidths[$i]
179 | $tableHeader += "$headerName | "
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 += ("| $computerName | ")
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 += ("$testResult | ")
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
--------------------------------------------------------------------------------