functions/get-d365installedhotfix.ps1
<#
.SYNOPSIS Get installed hotfix .DESCRIPTION Get all relevant details for installed hotfix .PARAMETER Path Path to the PackagesLocalDirectory Default path is the same as the aos service packageslocaldirectory .PARAMETER Model Name of the model that you want to work against Accepts wildcards for searching. E.g. -Model "*Retail*" Default value is "*" which will search for all models .PARAMETER Name Name of the hotfix that you are looking for Accepts wildcards for searching. E.g. -Name "7045*" Default value is "*" which will search for all hotfixes .PARAMETER KB KB number of the hotfix that you are looking for Accepts wildcards for searching. E.g. -KB "4045*" Default value is "*" which will search for all KB's .EXAMPLE Get-D365InstalledHotfix This will display all installed hotfixes found on this machine .EXAMPLE Get-D365InstalledHotfix -Model "*retail*" This will display all installed hotfixes found for all models that matches the search for "*retail*" found on this machine .EXAMPLE Get-D365InstalledHotfix -Model "*retail*" -KB "*43*" This will display all installed hotfixes found for all models that matches the search for "*retail*" and only with KB's that matches the search for "*43*" found on this machine .NOTES This cmdlet is inspired by the work of "Ievgen Miroshnikov" (twitter: @IevgenMir) All credits goes to him for showing how to extract these informations His blog can be found here: https://ievgensaxblog.wordpress.com The specific blog post that we based this cmdlet on can be found here: https://ievgensaxblog.wordpress.com/2017/11/17/d365foe-get-list-of-installed-metadata-hotfixes-using-metadata-api/ #> function Get-D365InstalledHotfix { [CmdletBinding(DefaultParameterSetName = 'Default')] param ( [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 1 )] [string] $BinPath = "$Script:BinDir\bin", [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 2 )] [string] $PackageDirectory = $Script:PackageDirectory, [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 3 )] [string] $Model = "*", [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 4 )] [string] $Name = "*", [Parameter(Mandatory = $false, ParameterSetName = 'Default', Position = 5 )] [string] $KB = "*" ) begin { } process { $StorageAssembly = Join-Path $BinPath "Microsoft.Dynamics.AX.Metadata.Storage.dll" $InstrumentationAssembly = Join-Path $BinPath "Microsoft.Dynamics.ApplicationPlatform.XppServices.Instrumentation.dll" Write-PSFMessage -Level Verbose -Message "Testing if the path exists or not." -Target $StorageAssembly if (Test-Path -Path $StorageAssembly -PathType Leaf) { Write-PSFMessage -Level Verbose -Message "Loading assembly" -Target $StorageAssembly Add-Type -Path $StorageAssembly } else { Write-PSFMessage -Level Host -Message "Unable to <c='em'>load necessary assembly</c>. Please ensure that the <c='em'>BinPath</c> exists and you have permissions to access it." Stop-PSFFunction -Message "Stopping because of missing assembly" return } Write-PSFMessage -Level Verbose -Message "Testing if the path exists or not." -Target $InstrumentationAssembly if (Test-Path -Path $InstrumentationAssembly -PathType Leaf) { Add-Type -Path $InstrumentationAssembly } else { Write-PSFMessage -Level Host -Message "Unable to <c='em'>load necessary assembly</c>. Please ensure that the <c='em'>BinPath</c> exists and you have permissions to access it." Stop-PSFFunction -Message "Stopping because of missing assembly" return } Write-PSFMessage -Level Verbose -Message "Testing if the cmdlet is running on a OneBox or not." -Target $Script:IsOnebox if ($Script:IsOnebox) { Write-PSFMessage -Level Verbose -Message "Machine is onebox. Will continue with DiskProvider." $diskProviderConfiguration = New-Object Microsoft.Dynamics.AX.Metadata.Storage.DiskProvider.DiskProviderConfiguration $diskProviderConfiguration.AddMetadataPath($PackageDirectory) $metadataProviderFactory = New-Object Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory $metadataProvider = $metadataProviderFactory.CreateDiskProvider($diskProviderConfiguration) Write-PSFMessage -Level Verbose -Message "MetadataProvider initialized." -Target $metadataProvider } else { Write-PSFMessage -Level Verbose -Message "Machine is NOT onebox. Will continue with RuntimeProvider." $runtimeProviderConfiguration = New-Object Microsoft.Dynamics.AX.Metadata.Storage.Runtime.RuntimeProviderConfiguration -ArgumentList $Script:PackageDirectory $metadataProviderFactory = New-Object Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory $metadataProvider = $metadataProviderFactory.CreateRuntimeProvider($runtimeProviderConfiguration) Write-PSFMessage -Level Verbose -Message "MetadataProvider initialized." -Target $metadataProvider } Write-PSFMessage -Level Verbose -Message "Initializing the UpdateProvider from the MetadataProvider." $updateProvider = $metadataProvider.Updates Write-PSFMessage -Level Verbose -Message "Looping through all modules from the MetadataProvider." foreach ($obj in $metadataProvider.ModelManifest.ListModules()) { Write-PSFMessage -Level Verbose -Message "Filtering out all modules that doesn't match the model search." -Target $obj if ($obj.Name -NotLike $Model) {continue} Write-PSFMessage -Level Verbose -Message "Looping through all hotfixes for the module from the UpdateProvider." -Target $obj foreach ($objUpdate in $updateProvider.ListObjects($obj.Name)) { Write-PSFMessage -Level Verbose -Message "Reading all details for the hotfix through UpdateProvider." -Target $objUpdate $axUpdateObject = $updateProvider.Read($objUpdate) Write-PSFMessage -Level Verbose -Message "Filtering out all hotfixes that doesn't match the name search." -Target $axUpdateObject if ($axUpdateObject.Name -NotLike $Name) {continue} Write-PSFMessage -Level Verbose -Message "Filtering out all hotfixes that doesn't match the KB search." -Target $axUpdateObject if ($axUpdateObject.KBNumbers -NotLike $KB) {continue} [PSCustomObject]@{ Model = $obj.Name Hotfix = $axUpdateObject.Name Applied = $axUpdateObject.AppliedDateTime KBs = $axUpdateObject.KBNumbers } } } } end { } } |