Hello
I created a custom function, added it to AppDeployToolkitExtensions.ps1.
If I open a powershell terminal and use the function ( after dot sourcing the main file) works perfectly.
But if I use it in a deployment, it doesn’t return anything. I see it running in the log, but there is not output (the variable in which I capture the output is empty).
Any idea why that would happen?
I used one of the built-in functions as a template.
The output command is: Write-Output -InputObject $MatchingInstalled
Again, works perfectly from command line. It outputs what I need. But not when I do the deployment.
Are you able to share your full extensions script? Might help to see the full thing.
Sure:
Function Get-InstalledAppInfo {
<#
.SYNOPSIS
Retrieves install related info about the app.
.DESCRIPTION
Retrieves information about installed applications by querying the registry. You can specify an application name.
Returns name, version and silent uninstall string.
.PARAMETER Name
The name of the application to retrieve information for. Performs a like match on the application display name.
.EXAMPLE
Get-InstalledAppInfo -Name 'Adobe Flash'
.NOTES
The function returns a single PSObject is there is only one entry or an array of PSObjects if there are multiple entries
To check if the function returned a single object or multiple, the .Count method can be used on the variable that will hold
the info returned by the function. $<var>.Count -eq $null is True for single PSObject and False for an array of PSObjects
.LINK
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $True)]
[ValidateNotNullOrEmpty()]
[string[]]$Name
)
Begin {
## Get the name of this function and write header
[string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
}
Process {
Write-Log -Message "Get Control Panel information for installed Application Name(s) [$($Name -join ', ')]..." -Source ${CmdletName}
# Search for matching apps in the uninstall registry keys
[psobject[]]$RawData = @()
$RawData = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-Object { $_.DisplayName -ne $Null -and $_.SystemComponent -ne "1" -and $_.DisplayName -like "*$Name*" } |
Select-Object DisplayName, Publisher, DisplayVersion, UninstallString, QuietUninstallString
# If the OS is 64 bit, also scan the Wow6432Node sub-key
if ([System.IntPtr]::Size -eq 8) {
# We have a 64 bit OS
$RawData += Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-Object { $_.DisplayName -ne $Null -and $_.SystemComponent -ne "1" -and $_.DisplayName -like "*$Name*" } |
Select-Object DisplayName, Publisher, DisplayVersion, UninstallString, QuietUninstallString
}
# If we have no data, return null
if ($RawData -eq $Null) {
Write-Output -InputObject $Null
}
else {
# Create a custom object with the desired properties for the installed applications and sanitize property details
[psobject[]]$MatchingInstalled = @()
ForEach ($RetApp in $RawData) {
Try {
[string]$AppDisplayName = ''
[string]$AppDisplayVersion = ''
[string]$AppPublisher = ''
## Bypass any updates or hotfixes
If ($RetApp.DisplayName -match '(?i)kb\d+') { Continue }
If ($RetApp.DisplayName -match 'Cumulative Update') { Continue }
If ($RetApp.DisplayName -match 'Security Update') { Continue }
If ($RetApp.DisplayName -match 'Hotfix') { Continue }
## Remove any control characters which may interfere with logging and creating file path names from these variables
$IllegalChars = [string][System.IO.Path]::GetInvalidFileNameChars()
$AppDisplayName = $RetApp.DisplayName -replace $IllegalChars, ''
$AppDisplayVersion = $RetApp.DisplayVersion -replace $IllegalChars, ''
$AppPublisher = $RetApp.Publisher -replace $IllegalChars, ''
if ($RetApp.QuietUninstallString -eq $Null) {
$AppUninstallString = $RetApp.UninstallString
}
else {
$AppUninstallString = $RetApp.QuietUninstallString
}
$MatchingInstalled += New-Object -TypeName 'PSObject' -Property @{
DisplayName = $AppDisplayName
DisplayVersion = $AppDisplayVersion
Publisher = $AppPublisher
UninstallString = $AppUninstallString
}
}
Catch {
Write-Log -Message "Failed to resolve application details from registry for [$AppDisplayName]. `n$(Resolve-Error)" -Severity 3 -Source ${CmdletName}
Continue
}
}
Write-Output -InputObject $MatchingInstalled
}
}
End {
Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
}
}
It is just a customised version of the Get-InstalledApplication function.
I used the Get-InstalledApplication as a template and just made a few changes.
I copied the function to Deploy-Application.ps1. It works from there.
Oh, now I see that you said to share the entire AppDeployToolkitExtensions.ps1 file. It is the standard one, I didn’t change anything other than adding the function above in the:
##*===============================================
##* FUNCTION LISTINGS
##*===============================================
##*===============================================
##* END FUNCTION LISTINGS
##*===============================================
section.
Did a bit more research and it seems that the problem is that:
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall*
doesn’t return anything.
I’m using functions from extensions.ps1 just fine here. In fact we have thousands of toolkits using them. If they didn’t work it would be a lot of problems. Your problem is probably elsewhere. Also, there is a newer version of this function in the toolkit now. Maybe you should make a simple function if you want to rule it out, with maybe just Write-Log inside the body of the function.
Also, Get-ItemProperty doesnt exist in older versions of powershell - 2.0 and older. After \Uninstall you need a backslash just like in your function above.
I belive I found the problem.
Get-ItemProperty exists in PowerShell 2.0 but it doesn’t work as it does in newer versions. See my test below:
You have to specifically set the path to HKLM and then query the info.
Yes! It is working now!
the location was the issue.
No, let me explain what you missed here.
HKLM: isnt the same as HKEY_LOCAL_MACHINE. If you see : after a name, that means its a PSDrive. If you do Get-PSDrive, you will see it there. It’s basically the same like your C: drive. It’s a shortcut to the real thing.If you use default ps commands where it only mentions Item like New-Item Get-Item Get-ItemProperty etc., it doesn’t know what type of “thing” you want to look up or create. Is it a file, a certificate or a registry? It defaults to files. So when you just put HKEY_LOCAL_MACHINE, it thinks you just want a file or disk with that name. In other words, it looks into the filesystem. You can specify what type of “thing” you’re referring to, by prefixing the path with Registry:: or FileSystem:: etc. HKLM: works because it gets replaced with Registry::HKEY_LOCAL_MACHINE.
Yes, you are correct.
But the location wasn’t the problem either. I found the real issue. It was the fact that AppDeployToolkitMain.ps1 strips all spaces from the AppName variable.
And I used that variable to filter the registry data. And, of course, in app names with spaces, I had an issue. I solved the problem. Now all works just fine. Thanks for your help.