Skip to content

Instantly share code, notes, and snippets.

@rileyz
Last active May 22, 2023 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rileyz/1786685955734ffee97a1c2e89567049 to your computer and use it in GitHub Desktop.
Save rileyz/1786685955734ffee97a1c2e89567049 to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Script to assist with deploying App-V packages to users, for user publishing based testing.
.DESCRIPTION
Intended Use
This script was produced to assist in publishing packages to users, removing the arduous task
of discovering the target users SID.
This is for user published based testing, not globally published applications testing.
Valid for App-V 5.0 SP2 Hotfix 5 and greater.
Example
Logon as the test user, launch an elevate PowerShell console and execute this script. The script
will discover all logged on users, even switched users. The Execution Policy must allow scripts
to run.
Run the script from a PowerShell or PowerShell ISE console. The App-V packages should be in the
current working directory of the console.
* PowerShell console.
AddAndPublish-AppvClientPackageToSID.ps1
* PowerShell ISE.
Run script, or press F5.
About
I got disgruntled of having to discover a target SID when in depth testing was required for
complex applications. After numerous occasions this PowerShell script was created, while
resolving the need, it was also was a chance to improve my PowerShell skills.
Known Defects/Bugs
* The target needs to have an active session! No error trapping has been provided for this event.
Code Snippet Credits
* https://learn-powershell.net/2010/11/01/quick-hit-find-currently-logged-on-users
* https://blogs.msdn.microsoft.com/mpeder/2014/10/07/convert-sid-to-user-name-using-powershell
Version History
1.03 22/05/2023
Updated self-identity discovery to use .Net method.
Fixed missing leading zero's padding when user selection is greater than nine.
1.02 07/04/2022
Added support for packages with Deployment Configuration and User Configuration XML.
1.01 23/12/2016
Fixed Active Session detection by using different function.
Added detection for your elevated session.
Added support for packages with and without User Configuration XML.
Added support for multiple packages.
1.00 20/10/2016
Initial release.
Copyright & Intellectual Property
Feel to copy, modify and redistribute, but please pay credit where it is due.
Feedback is welcome, please contact me on LinkedIn.
.LINK
Author:.......http://www.linkedin.com/in/rileylim
Source Code:..https://gist.github.com/rileyz/1786685955734ffee97a1c2e89567049
Article:......http://www.itninja.com/blog/view/app-v-publish-to-user-sid-script
.EXAMPLE
PowerShell console.
AddAndPublish-AppvClientPackageToSID.ps1
PowerShell ISE.
Run script, or press F5.
#>
# Function List ###################################################################################
Function Get-ComputerSessions {
<#
.SYNOPSIS
Retrieves tall user sessions from local or remote server/s
.DESCRIPTION
Retrieves tall user sessions from local or remote server/s
.PARAMETER computer
Name of computer/s to run session query against.
.NOTES
Name: Get-ComputerSessions
Author: Boe Prox
DateCreated: 01Nov2010
.LINK
https://boeprox.wordpress.org
.EXAMPLE
Get-ComputerSessions -computer "server1"
Description
-----------
This command will query all current user sessions on 'server1'.
#>
[cmdletbinding(
DefaultParameterSetName = 'session',
ConfirmImpact = 'low'
)]
Param(
[Parameter(
Mandatory = $True,
Position = 0,
ValueFromPipeline = $True)]
[string[]]$computer
)
Begin {
$report = @()
}
Process {
ForEach($c in $computer) {
# Parse 'query session' and store in $sessions:
$sessions = query session /server:$c
1..($sessions.count -1) | % {
$temp = "" | Select Computer,SessionName, Username, Id, State, Type, Device
$temp.Computer = $c
$temp.SessionName = $sessions[$_].Substring(1,18).Trim()
$temp.Username = $sessions[$_].Substring(19,20).Trim()
$temp.Id = $sessions[$_].Substring(39,9).Trim()
$temp.State = $sessions[$_].Substring(48,8).Trim()
$temp.Type = $sessions[$_].Substring(56,12).Trim()
$temp.Device = $sessions[$_].Substring(68).Trim()
$report += $temp
}
}
}
End {
$report
}
} #End Function Get-ComputerSessions
#<<< End Of Function List >>>
# Start of script work ############################################################################
$DebugPreference = 'SilentlyContinue' #SilentlyContinue|Continue
$LoggedOnUsers = Get-ComputerSessions -computer localhost
$Counter = 0
$LoggedOnUsers | ForEach-Object {If ($_.Username)
{$User = $_.Username
Write-Debug "`$_ is $User"
$objUser = New-Object System.Security.Principal.NTAccount("$User")
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
Write-Debug "`$strSID is $strSID.Value"
$SID = $strSID.Value
$objSID = New-Object System.Security.Principal.SecurityIdentifier ("$SID")
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
Write-Debug "`$objUser is $objUser.Value"
$LoggedOnUsers[$Counter].Username = $objUser.Value}
$Counter++}
Write-Debug 'Loading up array with SIDs.'
$SIDArray = @()
$RegistryDataArray = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
Foreach ($Item in $RegistryDataArray)
{$SID = $Item.Name -replace "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"
Write-Debug "SID data found in registry: $SID."
$SIDArray += "$SID"}
Write-Debug 'Removing junk SIDs from the array.'
$RemoveKnownSIDArray = 'S-1-5-18','S-1-5-19','S-1-5-20'
Foreach ($Item in $RemoveKnownSIDArray)
{Write-Debug "Removing junk SID $Item."
$SIDArray = $SIDArray | Where-Object {$_ -ne "$Item"}}
Write-Debug 'Fetching user names from SIDs and checking for session.'
$SIDAndUserArray = @()
$LeadingZero = ([string]$SIDArray.Count).Length
$UniqueID = 0
Foreach ($Item in $SIDArray)
{$UniqueID ++
$objSID = New-Object System.Security.Principal.SecurityIdentifier ("$Item")
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
If ($LoggedOnUsers.Username -contains $objUser)
{$SessionFound = 'Yes'}
Else{$SessionFound = 'No'}
If ($([Security.Principal.WindowsIdentity]::GetCurrent().Name) -eq $objUser)
{$SessionFound = 'Yes'}
$SIDAndUserArray += @{ID="$(([string]$UniqueID).PadLeft($LeadingZero,'0'))";User="$objUser"; SID="$Item"; "ActiveSession"="$SessionFound"}
Write-Debug "Translating SID:$objSID to $objUser. Active: $SessionFound."}
Write-Debug 'Gathering App-V packages from current directory.'
$PackageArray = Get-ChildItem -Filter *.appv
If ($PackageArray.count -eq 0)
{Write-Warning 'No App-V packages detected to process.'}
Else{Write-Output 'This will user publish the following App-V packages:'
$PackageAndUserConfigArray = @()
$PackageArray | foreach {Write-Debug "Working on $($_.Name)"
If (Test-path ($_.BaseName + '_DeploymentConfig.xml'))
{Write-Debug 'XML found.'
$DeploymentConfigXMLCheck = 'Yes'}
Else{Write-Debug 'XML not found.'
$DeploymentConfigXMLCheck = 'No'}
If (Test-path ($_.BaseName + '_UserConfig.xml'))
{Write-Debug 'XML found.'
$UserConfigXMLCheck = 'Yes'}
Else{Write-Debug 'XML not found.'
$UserConfigXMLCheck = 'No'}
$PackageAndUserConfigArray +=@{Package="$($_.Name)";DeploymentConfigXml="$DeploymentConfigXMLCheck";UserConfigXml="$UserConfigXMLCheck"}}
$PackageAndUserConfigArray | ForEach-Object {New-Object PSObject -Property $_} | Format-Table -Property Package,DeploymentConfigXml,UserConfigXml
Write-Debug 'Showing output for user selection.'
#$SIDAndUserArray | ForEach-Object {New-Object PSObject -Property $_} | Format-Table -Property ID,User,SID,ActiveSession
$SIDAndUserArray | ForEach-Object {New-Object PSObject -Property $_} | Format-Table -Property ID,User,ActiveSession
If ($PackageArray.count -gt 1) {Write-Warning 'This will publish multiple App-V packages to the user.'}
Write-Output ''
Write-Output 'Publish these App-V application/s to'
Do {$Input = Read-Host '?'
If ($SIDAndUserArray[$($Input - 1)].ActiveSession -eq 'No')
{Write-Warning 'Invalid, user has no active session.'
$Input = $null}}
Until ($Input -gt 0 -and $Input -le $SIDAndUserArray.Count)
$FilteredSIDAndUserArray = $SIDAndUserArray[$($Input - 1)]
$DisplayName = ($FilteredSIDAndUserArray.User | Out-String) -replace "`n|`r"
$PackageAndUserConfigArray | foreach {$AppvPackage = Get-ChildItem $_.Package
switch ("$($_.DeploymentConfigXml),$($_.UserConfigXml)") {
'Yes,No' {Write-Debug "Publishing $($AppvPackage.BaseName) with Deployment Configuration XML."
$PackageDeploymentConfig = $AppvPackage.BaseName + '_DeploymentConfig.xml'
Add-AppvClientPackage -Path $AppvPackage -DynamicDeploymentConfiguration $PackageDeploymentConfig | Publish-AppvClientPackage -UserSID $FilteredSIDAndUserArray.SID -DynamicUserConfigurationType UseDeploymentConfiguration}
'No,Yes' {Write-Debug "Publishing $($AppvPackage.BaseName) with User Configuration XML."
$PackageUserConfig = $AppvPackage.BaseName + '_UserConfig.xml'
Add-AppvClientPackage -Path $AppvPackage | Publish-AppvClientPackage -UserSID $FilteredSIDAndUserArray.SID -DynamicUserConfigurationPath $PackageUserConfig}
'Yes,Yes' {Write-Debug "Publishing $($AppvPackage.BaseName) with Deployment and User Configuration XML."
$DynamicConfigurationWarning = $true
$PackageDeploymentConfig = $AppvPackage.BaseName + '_DeploymentConfig.xml'
$PackageUserConfig = $AppvPackage.BaseName + '_UserConfig.xml'
Add-AppvClientPackage -Path $AppvPackage -DynamicDeploymentConfiguration $PackageDeploymentConfig | Publish-AppvClientPackage -UserSID $FilteredSIDAndUserArray.SID -DynamicUserConfigurationPath $PackageUserConfig}
'No,No' {Write-Debug "Publishing $($AppvPackage.BaseName) without any XML configurations."
Add-AppvClientPackage -Path $AppvPackage | Publish-AppvClientPackage -UserSID $FilteredSIDAndUserArray.SID}}}
If ($DynamicConfigurationWarning) {
Write-Warning 'Detected Deployment and User Configuration XML for a package.'
Write-Warning 'Note, User Configuration overrides Deployment Configuration, and Deployment Configuration overrides Manifest.'}}
#<<< End of script work >>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment