Get-MsiPropertyValue.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<#PSScriptInfo
 
.Version
    1.1
.Guid
    dc64634e-86a9-4ed5-bc7f-f2a55fa3bb0a
.Author
    Thomas Malkewitz @dotps1
.Tags
    MSI, PSCustomObject
.ProjectUri
    https://github.com/dotps1/PSFunctions
.ReleaseNotes
    Move Out-Null cmdlets to left side of pipeline for reduced performance cost.
 
#>


<#
 
.Synopsis
    Gets a property value from a Windows Installer Database.
.Description
    Opens a Windows Installer Database (.msi) and queries for the specified property value.
.Inputs
    System.String
.Outputs
    System.String
.Parameter Path
    System.String
    The location of the Windows Installer Database.
.Parameter Property
    System.String
    The Property to get the value of.
.Example
    PS C:\> Get-MsiPropertyValue -Path .\jre1.8.0_121.msi -Property ProductVersion, ProductCode
 
    Name ProductVersion ProductCode
    ---- -------------- -----------
    jre1.8.0_121.msi 8.0.1210.13 {26A24AE4-039D-4CA4-87B4-2F32180121F0}
.Example
    PS C:\> Get-ChildItem -Path ".\Installers" -Filter "*.msi" | Select -ExpandProperty FullName | Get-MsiPropertyValue -Property ProductVersion
     
    Name ProductVersion ProductCode
    ---- -------------- -----------
    jre1.8.0_101.msi 8.0.1010.13 {26A24AE4-039D-4CA4-87B4-2F32180101F0}
    jre1.8.0_111.msi 8.0.1110.14 {26A24AE4-039D-4CA4-87B4-2F32180111F0}
    jre1.8.0_121.msi 8.0.1210.13 {26A24AE4-039D-4CA4-87B4-2F32180121F0}
.Link
    https://dotps1.github.io
.Link
    https://www.powershellgallery.com/packages/Get-MsiPropertyValue
.Link
    https://grposh.github.io
 
#>


    
[CmdletBinding()]
[OutputType(
    [PSCustomObject]
)]

param (
    [Parameter(
        Mandatory = $true,
        ValueFromPipeLine = $true,
        ValueFromPipelineByPropertyName = $true
    )]
    [ValidateScript({
        if (([System.IO.FileInfo]$_).Extension -eq ".msi") {
            $true
        } else {
            throw "Path must be a Windows Installer Database (*.msi) file."
        }
    })]
    [String[]]
    $Path,

    [Parameter(
        Mandatory = $true,
        ValueFromPipelineByPropertyName = $true
    )]
    [String[]]
    $Property
)

begin {
    $windowsInstaller = New-Object -ComObject WindowsInstaller.Installer
}

process {
    foreach ($pathValue in $Path) {
        try {
            $item = Get-Item -Path $pathValue -ErrorAction Stop
                
            $database = $windowsInstaller.GetType().InvokeMember(
                "OpenDatabase", "InvokeMethod", $null, $windowsInstaller, ($item.FullName, 0)
            )

            $output = [PSCustomObject]@{
                Name = $item.Name
            }

            foreach ($propertyValue in $Property) {
                $view = $database.GetType().InvokeMember(
                    "OpenView", "InvokeMethod", $null, $database, "SELECT Value FROM Property WHERE Property = '$propertyValue'"
                )

                Out-Null -InputObject ($view.GetType().InvokeMember(
                    "Execute", "InvokeMethod", $null, $view, $null
                ))

                $record = $view.GetType().InvokeMember(
                    "Fetch", "InvokeMethod", $null, $view, $null
                )

                $value = $record.GetType().InvokeMember(
                    "StringData", "GetProperty", $null, $record, 1
                )

                Add-Member -InputObject $output -Name $propertyValue -Value $value -MemberType NoteProperty
            }

            Out-Null -InputObject ($database.GetType().InvokeMember(
                "Close", "InvokeMethod", $null, $view, $null
            ))

            Write-Output -InputObject $output
        } catch {
            Write-Error $_
            continue
        }
    }
}

end {
    Out-Null -InputObject ([System.Runtime.InteropServices.Marshal]::ReleaseComObject(
        $windowsInstaller
    ))
}