Here’s a quick list of Powershell commands I find myself using frequently. I’ll keep this updated.
Get a list of all brokered connections
Get-BrokerConnectionLog | Sort BrokeringTime
I always sort by BrokeringTime because the order appears to be odd otherwise because the log is updated with the initial brokering time as well as the EndTime.
Add an application to multiple delivery groups
Add-BrokerApplication -Name "AppNameHere" -DesktopGroup "NewDesktopGroupHere"
Adding an application to multiple desktop groups is 100% supported, it’s just not exposed in the GUI as of XenApp 7.5. Otherwise, if you try to add an application that already exists, you’ll get “Microsoft Word_1”. Also note when you do this, you can also set a priority to different desktop group- by default, the priority is added as zero – take a look:
PS C:\Windows\system32> Get-BrokerApplication -Name "Notepad" ApplicationType : HostedOnDesktop AssociatedDesktopGroupPriorities : {0, 0} AssociatedDesktopGroupUids : {1, 2} AssociatedUserFullNames : {Domain Users, Jake Rutski} AssociatedUserNames : {lab\Domain Users, lab\jrutski} AssociatedUserUPNs : {, [email protected]} BrowserName : Notepad ClientFolder : AppCategory CommandLineArguments :
To set a different priority, use the ‘-priority’ argument:
Add-BrokerApplication -name "notepad" -DesktopGroup "Test Delivery Group" -Priority 5
View the SQL DB info for the XenDesktop site
Get-BrokerDBConnection Server=TESTSQL1;Initial Catalog=CitrixTestSite;Integrated Security=True
Monitoring Scripts
This script was used with a monitoring solution to return the count of unregistered machines, not in maintenance mode, powered on, and with a user assigned to the desktop:
(Get-BrokerDesktop -MaxRecordCount 2000 -AdminAddress yourddc.goes.here | Where {($_.RegistrationState -eq "Unregistered") -and ($_.AssociatedUserNames) -and !($_.InMaintenanceMode) -and ($_.PowerState -eq "On")}).Count
(Get-BrokerSession -SessionState Disconnected -AdminAddress yourddc.goes.here | Where {$_.SessionStateChangeTime -gt ((Get-Date).AddMinutes(-5))}).Count
Static Machine Addition
$NewVMObj = Get-ADComputer -Server your.domain.controller -Filter {Name -eq $NewVMName} Set-HypAdminConnection -AdminAddress "yourddc.goes.here" $XDVMId = (Get-Item "XDHyp:\Connections\Your Cluster\Your.datacenter\$($NewCluster).cluster\$($NewVMName).vm").Id # Add machine to machine catalog; add user to machine New-BrokerMachine -AdminAddress "yourddc.goes.here" -CatalogUid 3 -HostedMachineId $XDVMId -HypervisorConnectionUid 2 -MachineName $NewVMObj.SID Add-BrokerUser -AdminAddress "yourddc.goes.here" -Machine (Get-BrokerMachine -SID $NewVMObj.SID).Uid -Name "YOURDOMAIN\$($NewUser)" # Add machine to desktop group; Get-BrokerMachine -SID $NewVMObj.SID | Add-BrokerMachine -AdminAddress "yourddc.goes.here" -DesktopGroup "Your Desktop Group Here"
XenDesktop Machines that have not been logged in to in the past XX days
Get-BrokerDesktop -MaxRecordCount 2000 | Where {((Get-Date) - $_.LastConnectionTime).Days -gt 60} | sort LastConnectionTime | Select DNSName,LastConnectionTime,@{Name="UserName";Expression={$UserN = $_.AssociatedUserNames.Replace("YOURDOMAINHERE\",""); $UserObj = Get-ADUser -Filter {Name -eq $UserN}; "$($UserObj.GivenName) $($UserObj.Surname)"}}
One-liner to get a listing of all users that have not logged into their XD desktop in 60 days or more – this is for static desktops or XD PvD.
Requires:
- XenDesktop PowerShell SDK (studio commandlets)
- AD Powershell commandlets
asnp Citrix* Get-BrokerDesktop -MaxRecordCount 2000 | Where {((Get-Date) - $_.LastConnectionTime).Days -gt 60} | sort LastConnectionTime | Select DNSName,LastConnectionTime,@{Name="UserName";Expression={$UserN = $_.AssociatedUserFullNames.Replace("DOMAINHERE\",""); $UserObj = Get-ADUser -Filter {Name -eq $UserN}; "$($UserObj.GivenName) $($UserObj.Surname)"}}
Notes:
- Use MaxRecordCount for large environments
- Replace “DOMAINHERE\” with your domain
Updating MDT OS Images with WSUS
#------------------- # WIM offline updater # Inspired by: https://technet.microsoft.com/en-us/magazine/hh825626.aspx # Author: Jake Rutski # @JRutski blogs.serioustek.net # Use at your own risk; I am not responsible for any issues caused by this script #------------------- # Variables $imagePath = "\\storage\Software\MDT\Operating Systems\Windows Server 2012 R2\sources\install.wim" $wsusPath = "D:\WSUS\WsusContent" $mountPath = "C:\Mount" $imageIndex = 4 # Check for root # http://blogs.technet.com/b/heyscriptingguy/archive/2011/05/11/check-for-admin-credentials-in-a-powershell-script.aspx If(!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Host "`nThis script is not running as administrator - this is required to use DISM`n" Exit } # Mount the image Mount-WindowsImage -ImagePath $imagePath -Path $mountPath -Index $imageIndex # Get the update files and install them offline foreach($cabFile in (gci $wsusPath -Filter *.cab -Recurse)) { Add-WindowsPackage -PackagePath $cabFile.FullName -Path C:\Mount } # Dismount and save the image Dismount-WindowsImage -Path C:\Mount -Save
Cleaning up Static XenDesktop VMs (including PowerCLI)
These series of cmdlets will remove the desktop from the delivery group and machine catalog, remove the object from AD, and delete the VM from vCenter. Replace ‘Domain\ComputerName’ with the appropriate strings; if you are not running on the DDC or not already pointed at it, make sure to add the ‘adminaddress’ parameter. *Note: these commands remove and delete things, so BE CAREFUL!
$XDesktop = Get-BrokerMachine -MachineName Domain\ComputerName $XDesktop | Set-BrokerMachineMaintenanceMode -MaintenanceMode $True Stop-BrokerSession (Get-BrokerDesktop -DNSName machinename.domain.com).SessionUid New-BrokerHostingPowerAction -MachineName Domain\ComputerName -Action shutdown $XDesktop | Remove-BrokerMachine -DesktopGroup GroupUID -Force $XDesktop | Remove-BrokerMachine -Force Remove-ADComputer ComputerName Get-VM VMName | Remove-VM -DeleteFromDisk
Creating a single text file from multiple files
This one-liner takes all text files in a directory and appends them all to a single new file.
Get-Content "C:\Test\Files\*.txt" -Force | Set-Content "C:\Test\Files\newFile.txt"
Copying all users in one AD group to another AD group
Simple one-liner to copy users from one group to another – requires AD Powershell plugins.
Get-ADGroupMember NameOfSourceGroup | % {Add-ADGroupMember NameOfDestinationGroup -Members $_}
Output all DFSN Targets from a common root
*Requires DFS tools
Get-DfsnFolder -Path "\\SomeDomain.com\files\*" | % {Get-DfsnFolderTarget -Path $_.Path | Select Path,NamespacePath,State,TargetPath,ReferralPriorityClass}
Basic IPMI Commands
Works on SuperMicro BMC IPMI on X9\X10 boards
$creds = Get-Credential # To start the server Get-PcsvDevice -TargetAddress your.ip.address.here -ManagementProtocol IPMI -Credential $creds | Start-PcsvDevice # To stop the server Get-PcsvDevice -TargetAddress your.ip.address.here -ManagementProtocol IPMI -Credential $creds | Stop-PcsvDevice
Uninstall from Windows Command Line
So this isn’t PowerShell, but it’s super useful.
wmic product get name ... wmic product where name="..." call uninstall
Duplicate file Cleanup for Plex Camera Uploads
See the full post here.
<# .SYNOPSIS Script to remove duplicate photos from the Plex Mobile Uploads directory .DESCRIPTION This script will enumerate all files in the Mobile Uploads directory, then find files that are the same size. A SHA1 hash is generated for each of these files to verify that they are the same image prior to being deleted. Files that have incorrect date formats (1970-01-01) or are hyphenated take precedence to be deleted, unless all duplicate files are formatted incorrectly, then the first file found to be duplicate will be deleted. .NOTES Script only looks for -1, -2 or -3 JPG files or -1 and -2 MP4 files More file types can be added to the Get-ChileItem -Include section if needed .PARAMETER delete If the 'delete' parameter is used, the script will delete files once hashed duplicates have been found #> param( [parameter(Mandatory=$false)] [switch]$delete=$false ) $logFile = "$([Environment]::GetFolderPath("mydocuments"))\DupeDeleteLog.txt" # Write to a log file in the current users MyDocs directory Function Write-Log { Param([string]$logStr) Add-Content $logFile -Value $logStr } # User select location to find duplicate files Function Get-FolderName { Add-Type -AssemblyName System.Windows.Forms $FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog [void]$FolderBrowser.ShowDialog() $FolderBrowser.SelectedPath } Write-Log "$(Get-Date)" Write-Log "Waiting for input from user to select working directory..." $mypath = Get-FolderName # Initial log file notes If($delete){Write-Log "WARNING: File deletion will occur!"} Write-Log "Checking for duplicates in $($mypath)" Write-Log "Finding same size files and hashing them. This will take some time...." $dupeHash = foreach ($i in (Get-ChildItem -path $mypath -Recurse -Include "*.jpg","*.jpeg","*.mp4" | ? {( ! $_.ISPScontainer)} | Group Length | ? {$_.Count -gt 1} | Select -Expand Group | Select FullName, Length)){Get-FileHash -Path $i.Fullname -Algorithm SHA1} $dupeHashGrouped = $dupeHash | Group Hash | ? {$_.Count -gt 1} # Set confirm, if $delete param is not set, no delete will occur If(!($delete)){$delConfirm = "Y"} If($delete) { Write-Log "Waiting for input from user to confirm delete..." $delConfirm = Read-Host "WARNING: This script will now DELETE FILES. Press 'Y' to confirm you want to DELETE, or any other key to cancel" } If (($delConfirm -eq 'y') -or ($delConfirm -eq 'Y')) { foreach ($dhGroup in $dupeHashGrouped) { Write-Log "Current file hash: $($dhGroup.Group[0].Hash)" Write-Log "Matching files: $($dhGroup.Count)" $goodFile = $false $i = 1 foreach($matchFile in $dhGroup.Group.Path) { If($i -eq $dhGroup.Count -and (!($goodFile))) { #Last file, no good found...keeping Write-Log "Last file in group. Keeping: $($matchFile)" } ElseIf($matchFile -like "*1970*") { Write-Log "File in group contains invalid date 1970: $($matchFile) - will be deleted." If($delete){Remove-Item -Path $matchFile -Confirm:$false} } #modify if more duplicated hyphens are found ElseIf($matchFile -like "*-1.jpg" -or $matchFile -like "*-2.jpg" -or $matchFile -like "*-3.jpg" -or $matchFile -like "*-1.mp4" -or $matchFile -like "*-2.mp4") { Write-Log "File in group is hyphenated: $($matchFile) - will be deleted." If($delete){Remove-Item -Path $matchFile -Confirm:$false} } Else { If($goodFile) { #Already found valid file in group Write-Log "Deleting this file: $($matchFile) already have good file." If($delete){Remove-Item -Path $matchFile -Confirm:$false} } Else { #Don't have good file in group; keep Write-Log "Keeping: $($matchFile)" $goodFile = $true } } $i++ } Write-Log " " } } Else { Write-Log "Deletion cancelled by user" }
I wanted to run a question by you about the unregistered machines. We see the Orange Triangle on the unregistered VDI’s and I wrote a script similar to yours but check a couple extra options then reboots the machines.
I’m just looking for validation that I am checking for the valid options. Do I need to use all of them?
Below are the objects I query for to determine the status of the machines.
FaultState -ne ‘None’ `
-AND MachineInternalState -eq ‘Unregistered’ `
-AND PowerState -ne ‘Off’ `
-AND InMaintenanceMode -ne ‘True’ `
-AND RegistrationState -ne ‘Registered’ `
-AND SessionUserName -eq $null}|
Select-Object HostedMachineName, DesktopGroupName
Rob, I’d say it depends on exactly what scenario you’re trying to prevent as to which parameters you need to check, but it sounds similar. I created that to integrate with PRTG and provide a count of unregistered machines…keep in mind this was before I deployed PVS, so all of the machines were statically assigned and the images would continually go nuts, thus causing unregistrations, etc.
Thanx for this. These are helpful commands/scripts. I am new to powershell. We run XenDesktop 7.15. We publish applications to XenDesktops. I want to run Get-BrokerApplication to get a list of all the published applications, but I want the output to only show the PublishedName and the AssociatedUserName(s). How to I write the command/script to filter out all other details?
I need a command which will give the list of all published apps with respect to Delivery group for Citrix 7.15