Functions/LicenseManagement/Get-BcLicense.ps1
<#
.Synopsis Returns the key-value pairs from a Business Central license. .Description By default, the function retrieves the license from the ServerInstance, but the license can also be provided as a string or a file path. The function then extracts the license information as key-value pairs and returns the information as a PowerShell object. The function contains various validations to ensure that the license can be retrieved correctly. If the license cannot be retrieved for any reason, a warning message is displayed. .Example Get-BcLicense -ServerInstance BC210 <# Result: VOICEAccountNumber : 0000000 CreatedDate : 1-10-2023 05:23:10 Licensedto : MyCompany ProductVersion : 21 DevelopmentLicense : True Expires : 4-10-2023 00:00:00 #> #> function Get-BcLicense { [Alias('Get-LicenseDetails', 'Export-BcLicense')] [OutputType([psobject])] [CmdletBinding(DefaultParameterSetName="ServerInstance", SupportsShouldProcess)] param( # The name of the BC ServerInstance from which to export the BC License file. [Parameter( Mandatory=$true, Position = 0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ServerInstance")] [string] $ServerInstance, # The computer where the ServerInstance is running. Default is the local system. [Parameter( Position = 1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ServerInstance")] [string] $Computer = $env:COMPUTERNAME, # Specifies the ID of the tenant that the license is stored in. # This parameter is required unless the specified service instance is not configured to run multiple tenants. [Parameter( Position = 2, ValueFromPipeline=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ServerInstance")] [string] $Tenant = 'default', # The path to the BC license. The license details will be read from the specified file. [Parameter( Mandatory=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "LicencePath")] [string] $LicensePath, # A string array that contains the content of the BC license. [Parameter( Mandatory=$true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "LicenceString")] [Alias('RawLicense')] [string[]] $LicenseString, # Writes a warning to host if the license is older than the set age, default 60 days. [switch] $ValidateLicenseAge, # When the ValidateLicenseAge switch is set the license age is validated against RecommendedMaxDaysOld. [int] $RecommendedMaxDaysOld = 60 ) # Get the license as a string array. switch($PSCmdlet.ParameterSetName) { 'LicenceString' { [string[]] $licenseRaw = $LicenseString } 'LicencePath' { # Validations if(!(Get-Item -Path $LicensePath).Extension -in @('.flf', '.bclicense')){ 'Supplied file is not a Business Central license. Expected a file with the extension .flf or .bclicense.'| Write-Warning return } if(!(Test-Path $LicensePath)){ 'Could not find the Business Central license file on path: {0}.' -f $LicensePath | Write-Warning return } # Read file [string[]] $LicenseRaw = Get-Content -Path $LicensePath -raw } 'ServerInstance' { # Get the ServerInstance object. $serverInstanceObj = Get-BCServerInstance $ServerInstance -Computer $Computer if(!$serverInstanceObj){ 'Could not find the ServerInstance {0}.' -f $ServerInstance | Write-Warning return } # Validations if($serverInstanceObj.state -ne 'running'){ 'Cannot export license from ServerInstance {0} because the service is not started.' -f $ServerInstance | Write-Warning return } # Scriptblock is used to load BC modules into a separate PS session and to add compatibility for Computer param. [scriptblock] $scriptBlock = { param( [string[]] $BcModulesPath, [string] $ServerInstance, [string] $Tenant ) $BcModulesPath | Import-Module -Force Export-NAVServerLicenseInformation -ServerInstance $ServerInstance -Tenant $Tenant -WhatIf:$false -Confirm:$false } $additionParams = @{} if(-not $serverInstanceObj._isLocalService){ $additionParams = @{'ComputerName' = $serverInstanceObj.ComputerName} } # Execute scriptblock to export BC license from ServerInstance try{ [string[]] $licenseRaw = Invoke-Command @additionParams -ScriptBlock $scriptBlock -ErrorAction Stop -ArgumentList @( $serverInstanceObj.GetBcPsModules(), $serverInstanceObj.ServerInstance, $Tenant) } catch{ Write-Error $_ } } } if(!$licenseRaw){ 'Could not export the license file from ServerInstance {0}' -f $ServerInstance | Write-Warning return } # Extract key-value pairs from the string array. $regex = '(?<key>\w+(?:\s\w+){0,3})\s*:\s(?<value>.*)\r\n' $result = $licenseRaw | Select-String -Pattern $regex -AllMatches $licenseProperties = @{} foreach ($match in $result.Matches){ # Skip Country Code property if($match.Groups['key'].Value -eq 'Country Code'){ continue } # Add key-value pair to hashtable $licenseProperties += @{ $match.Groups['key'].Value.Replace(' ', '') = $match.Groups['value'].Value } } # Add additional properties $licenseProperties += @{ 'DevelopmentLicense' = $( if($licenseProperties.Expires){$true} else{$false}) } # Validate if required keys are extracted $requiredKeys = @('VOICEAccountNumber', 'CreatedDate', 'Licensedto', 'ProductVersion', 'DevelopmentLicense') $requiredKeys | ForEach-Object { if(!$licenseProperties.ContainsKey($_)){ $message = 'Could not extract key {0} from the Business Central license file.' -f $_ Write-Warning $message $return = $true break } } if($return){return} # Parse the date values into DateTime $dateElements = $licenseProperties.CreatedDate.Split(' ') $createDate = '{0} {1}' -f $dateElements[0], $dateElements[1] $dateFormat = 'M/d/yyyy H:mm:ss' $licenseProperties.CreatedDate = [datetime]::ParseExact($createDate, $dateFormat, $null) if($licenseProperties.DevelopmentLicense){ $dateFormat = 'M/d/yyyy' $licenseProperties.Expires = [datetime]::ParseExact($licenseProperties.Expires, $dateFormat, $null) } # Write warning when the license is more than 60 days old. if($ValidateLicenseAge){ $elapsedTime = ((Get-Date) - $licenseProperties.CreatedDate) if($elapsedTime.Days -gt $RecommendedMaxDaysOld){ $message = 'The supplied license was created {0} days ago. It is recommended to update the license at least once every {1} days.' -f $elapsedTime.Days, $RecommendedMaxDaysOld Write-Warning $message } } # Convert hashtable to PSObject $license = New-Object PSObject -Property $licenseProperties | Sort-Object -Property $returnKeys # Create a string array with properties that will be visible by default. [string[]] $returnKeys = $requiredKeys if($licenseProperties.DevelopmentLicense){ $returnKeys += 'Expires' } # Add list of properties that will be visible by default. Properties not in the list will be hidden by default. [Management.Automation.PSMemberInfo[]] $PSStandardMembers = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',$returnKeys) $license | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers return $license } Export-ModuleMember -Function Get-BcLicense -Alias @('Get-LicenseDetails', 'Export-BcLicense') |