Set-Win32Software.ps1
<#PSScriptInfo
.GUID 5b05dd91-2073-4bc8-b598-940e6f65e89c .VERSION 1.0.0.2 .AUTHOR Michael Haken .COMPANYNAME BAMCIS .COPYRIGHT (c) 2016 BAMCIS. All rights reserved. .TAGS WMI Software .LICENSEURI https://contoso.com/License .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Updated file path variables. #> <# .SYNOPSIS Creates the Win32_Software and Win32_Software64 WMI classes on the local computer or a remote computer. .DESCRIPTION The cmdlet creates two custom WMI classes for enumerating installed software from the standard registry provider. It creates a temporary mof file on the SystemDrive and calls mofcomp.exe to add the WMI class. .PARAMETER ComputerName The computer to create the custom WMI classes on. This defaults to localhost. If the target is a remote computer, Invoke-Command is used to execute the underlying function. .PARAMETER TempFilePath Where the temporary mof file is stored, this defaults to %SYSTEMDRIVE%\win32_software.mof. .PARAMETER Credential The credential to use to connect to a remote computer. This parameter is ignored if the ComputerName is localhost, ".", or 127.0.0.1. .EXAMPLE Set-Win32Software Creates the two custom WMI classes on the local computer. .EXAMPLE Set-Win32Software -ComputerName server1.contoso.com -Credential (Get-Credential) Creates the two custom WMI classes on server1.contoso.com. .INPUTS System.String, System.String .OUTPUTS None .NOTES AUTHOR: Michael Haken LAST UPDATE: 3/24/2016 #> Param ( [Parameter(Position=0,ValueFromPipeline=$true)] [string]$ComputerName = "localhost", [Parameter(Position=1,ValueFromPipelineByPropertyName=$true)] [string]$TempFilePath = "$env:SYSTEMDRIVE\win32_software.mof", [Parameter(Position=2)] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) Function Set-Win32SoftwareWMIClass { <# .SYNOPSIS Creates the Win32_Software and Win32_Software64 WMI classes. .DESCRIPTION The cmdlet creates two custom WMI classes for enumerating installed software from the standard registry provider. It creates a temporary mof file on the SystemDrive and calls mofcomp.exe to add the WMI class. .PARAMETER TempFilePath Where the temporary mof file is stored, this defaults to %SYSTEMDRIVE%\win32_software.mof. .EXAMPLE Set-Win32SoftwareWMIClass Creates the two custom WMI classes. .EXAMPLE Set-Win32SoftwareWMIClass -TempFilePath c:\file.mof Creates the two custom WMI classes and stores the temporary mof file at c:\file.mof. .INPUTS System.String .OUTPUTS None .NOTES AUTHOR: Michael Haken LAST UPDATE: 3/24/2016 #> [CmdletBinding()] Param( [Parameter(Position=0,ValueFromPipeline=$true)] [string]$TempFilePath = "$env:SYSTEMDRIVE\win32_software.mof" ) Begin { if (!([System.Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { throw "Script must be run with administrator privileges." } if ([System.String]::IsNullOrEmpty($TempFilePath)) { $TempFilePath = "$env:SYSTEMDRIVE\win32_software.mof" } $WmiClass = "Win32_Software" $WmiClass64 = "Win32_Software64" $FileContent = @" #pragma namespace("\\\\.\\root\\cimv2") #PRAGMA AUTORECOVER [dynamic, provider("RegProv"), ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")] class $WmiClass64 { [key] string KeyName; [read, propertycontext("DisplayName")] string DisplayName; [read, propertycontext("DisplayVersion")] string DisplayVersion; [read, propertycontext("InstallDate")] string InstallDate; [read, propertycontext("InstallSource")] string InstallSource; [read, propertycontext("UninstallString")] string UninstallString; [read, propertycontext("Publisher")] string Publisher; [read, propertycontext("Version")] Uint32 Version; [read, propertycontext("VersionMajor")] Uint32 VersionMajor; [read, propertycontext("VersionMinor")] Uint32 VersionMinor; [read, propertycontext("EstimatedSize")] Uint32 EstimatedSize; }; [dynamic, provider("RegProv"), ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")] class $WmiClass { [key] string KeyName; [read, propertycontext("DisplayName")] string DisplayName; [read, propertycontext("DisplayVersion")] string DisplayVersion; [read, propertycontext("InstallDate")] string InstallDate; [read, propertycontext("InstallSource")] string InstallSource; [read, propertycontext("UninstallString")] string UninstallString; [read, propertycontext("Publisher")] string Publisher; [read, propertycontext("Version")] Uint32 Version; [read, propertycontext("VersionMajor")] Uint32 VersionMajor; [read, propertycontext("VersionMinor")] Uint32 VersionMinor; [read, propertycontext("EstimatedSize")] Uint32 EstimatedSize; }; "@ } Process { $Temp = Set-Content -Path $TempFilePath -Value $FileContent $Software = Get-WmiObject -Class $WmiClass -List -Namespace "root\cimv2" if ($Software -ne $null) { Remove-WmiObject -Class $WmiClass | Out-Null } $Software64 = Get-WmiObject -Class $WmiClass64 -List -Namespace "root\cimv2" if ($Software64 -ne $null) { Remove-WmiObject -Class $WmiClass64 | Out-Null } $Temp = Start-Process -FilePath ($env:SystemRoot + "\system32\wbem\mofcomp.exe") -ArgumentList @($TempFilePath) -WindowStyle Hidden -Wait $Counter = 0 while ($true) { try { Remove-Item -Path $TempFilePath -ErrorAction Stop -Force | Out-Null break } catch [Exception] { if ($Counter -gt 30) { Write-Warning "Timeout waiting to delete the temporary mof file, delete manually." break } Start-Sleep -Seconds 1 $Counter++ } } } End { Write-Host "WMI class creation complete." } } if ([System.String]::IsNullOrEmpty($TempFilePath)) { $TempFilePath = "$env:SYSTEMDRIVE\win32_software.mof" } if (![System.String]::IsNullOrEmpty($ComputerName) -and ($ComputerName.ToLower() -ne "localhost") -and ($ComputerName -ne ".") -and ($ComputerName -ne "127.0.0.1")) { Invoke-Command -ComputerName $ComputerName -ScriptBlock ${function:Set-Win32SoftwareWMIClass} -ArgumentList @($TempFilePath) -Credential $Credential } else { Set-Win32SoftwareWMIClass -TempFilePath $TempFilePath } |