Retail POS Offline Service Discovery

Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Discovery.EnterprisePosOfflineServiceInstanceDiscovery (Discovery)

Discovers instances of Retail POS Offline Service

Knowledge Base article:

Summary

Discovers instances of Retail POS Offline Service.

Element properties:

TargetMicrosoft.Windows.OperatingSystem
EnabledTrue
Frequency28800
RemotableFalse

Object Discovery Details:

Discovered Classes and their attribuets:

Member Modules:

ID Module Type TypeId RunAs 
EnterprisePosOfflineServiceDiscovery DataSource Microsoft.Windows.TimedPowerShell.DiscoveryProvider Default

Source Code:

<Discovery ID="Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Discovery.EnterprisePosOfflineServiceInstanceDiscovery" Enabled="true" Target="Windows!Microsoft.Windows.OperatingSystem" ConfirmDelivery="true" Remotable="false" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService"/>
</DiscoveryTypes>
<DataSource ID="EnterprisePosOfflineServiceDiscovery" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider">
<IntervalSeconds>28800</IntervalSeconds>
<SyncTime/>
<ScriptName>EnterprisePosOfflineServiceDiscovery.ps1</ScriptName>
<ScriptBody><Script>&lt;#
SAMPLE CODE NOTICE

THIS SAMPLE CODE IS MADE AVAILABLE AS IS. MICROSOFT MAKES NO WARRANTIES, WHETHER EXPRESS OR IMPLIED,
OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OR CONDITIONS OF MERCHANTABILITY.
THE ENTIRE RISK OF THE USE OR THE RESULTS FROM THE USE OF THIS SAMPLE CODE REMAINS WITH THE USER.
NO TECHNICAL SUPPORT IS PROVIDED. YOU MAY NOT DISTRIBUTE THIS CODE UNLESS YOU HAVE A LICENSE AGREEMENT WITH MICROSOFT THAT ALLOWS YOU TO DO SO.
#&gt;

param($target, $element, $computerName)
# this constant is used for logger initialization
$kScriptName = "EnterprisePosOfflineServiceDiscovery.ps1"
#Logging.psm1#

## Event codes
### RetailServerInstanceDiscovery
$kRetailServerInstanceDiscoveryStartedToRun = 10000
$kRetailServerInstanceDiscoveryRegistryKeyFound = 10001
$kRetailServerInstanceDiscoveryNewInstanceAddedToDiscoveryData = 10002
$kRetailServerInstanceDiscoveryNoRegistryKeyFound = 10003
$kRetailServerInstanceDiscoveryFinishedSuccessfully = 10004
$kRetailServerInstanceDiscoveryFinishedWithError = 10005

### RealtimeServiceInstanceDiscovery
$kRealtimeServiceInstanceDiscoveryStartedToRun = 10020
$kRealtimeServiceInstanceDiscoveryRegistryKeyFound = 10021
$kRealtimeServiceInstanceDiscoveryAddedToDiscoveryData = 10022
$kRealtimeServiceInstanceDiscoveryNoRegistryKeyFound = 10023
$kRealtimeServiceInstanceDiscoveryFinishedSuccessfully = 10024
$kRealtimeServiceInstanceDiscoveryFinishedWithError = 10025

### AsyncServerReplicationJobDiscovery
$kAsyncServerReplicationJobDiscoveryReplicationJobFound = 10050
$kAsyncServerReplicationJobDiscoveryNoReplicationJobsFound = 10051
$kAsyncServerReplicationJobDiscoveryNoEventWithReplicationJobs = 10052
$kAsyncServerReplicationJobDiscoveryStartedToRun = 10053
$kAsyncServerReplicationJobDiscoveryNoAOSInstancesFound = 10054
$kAsyncServerReplicationJobDiscoveryNoAOSRegistryKeysFound = 10055
$kAsyncServerReplicationJobDiscoveryFinishedSuccessfully = 10056
$kAsyncServerReplicationJobDiscoveryFinishedWithError = 10057
$kAsyncServerReplicationJobDiscoveryReplicationJobsEventId = 10065 # This event is generated by Dynamics Server

### SharePointECommerceDiscovery
$kSharePointECommerceDiscoveryStartedToRun = 10080
$kSharePointECommerceDiscoveryFinishedSuccessfully = 10081
$kSharePointECommerceDiscoveryFinishedWithError = 10082
$kSharePointECommerceDiscoveryFarmFound = 10083
$kSharePointECommerceDiscoveryFarmNotFound = 10084
$kSharePointECommerceDiscoveryECommerceDeploymentFound = 10085
$kSharePointECommerceDiscoveryECommerceDeploymentNotFound = 10086
$kSharePointECommerceDiscoveryECommerceWebAppsFound = 10087
$kSharePointECommerceDiscoveryECommerceWebAppsNotFound = 10088
$kSharePointECommerceDiscoveryECommerceTimerJobsFound = 10089
$kSharePointECommerceDiscoveryECommerceTimerJobsNotFound = 10090
$kSharePointECommerceDiscoveryECommerceWebAppDiscoveryDataAdded = 10091
$kSharePointECommerceDiscoveryECommerceTimerJobDiscoveryDataAdded = 10091

### CdxSynchServiceClientDiscovery
$kCdxSynchServiceClientDiscoveryStartedToRun = 10100
$kCdxSynchServiceClientDiscoveryRootKeyFound = 10101
$kCdxSynchServiceClientDiscoveryFailedToEvaluateErrorCountingPeriod = 10102
$kCdxSynchServiceClientDiscoveryNewInstanceDiscovered = 10103
$kCdxSynchServiceClientDiscoveryNoRootKeyFound = 10104
$kCdxSynchServiceClientDiscoveryFinishedSuccessfully = 10105
$kCdxSynchServiceClientDiscoveryFinishedWithError = 10106

### CdxSynchServiceServerDiscovery
$kCdxSynchServiceServerDiscoveryStartedToRun = 10110
$kCdxSynchServiceServerDiscoveryRootKeyFound = 10111
$kCdxSynchServiceServerDiscoveryNewInstanceDiscovered = 10112
$kCdxSynchServiceServerDiscoveryNoRootKeyFound = 10113
$kCdxSynchServiceServerDiscoveryFinishedSuccessfully = 10114
$kCdxSynchServiceServerDiscoveryFinishedWithError = 10115

### RetailServerChannelDBConnectionDiscovery
$kRetailServerChannelDBConnectionDiscoveryStartedToRun = 10120
$kRetailServerChannelDBConnectionDiscoverySearchingSuccessEvents = 10121
$kRetailServerChannelDBConnectionDiscoverySearchingErrorEvents = 10122
$kRetailServerChannelDBConnectionDiscoveryNewInstanceFound = 10123
$kRetailServerChannelDBConnectionDiscoveryNoInstancesFound = 10124
$kRetailServerChannelDBConnectionDiscoveryFinishedSuccessfully = 10125
$kRetailServerChannelDBConnectionDiscoveryFinishedWithError = 10126

### HardwareStationDiscovery
$kHardwareStationDiscoveryStartedToRun = 10140
$kHardwareStationDiscoveryRegistryKeyFound = 10141
$kHardwareStationDiscoveryNewInstanceAddedToDiscoveryData = 10142
$kHardwareStationDiscoveryNoRegistryKeyFound = 10143
$kHardwareStationDiscoveryFinishedSuccessfully = 10144
$kHardwareStationDiscoveryFinishedWithError = 10145

$kChannelDbConnectivityFailureEventId = 10200 # This event is generated by CRT Sdk (Retail Server, POS, eCommerce)
$kChannelDbConnectivitySuccessEventId = 10201 # This event is generated by CRT Sdk (Retail Server, POS, eCommerce)

### ReplicationJobScheduleState
$kReplicationJobStateStartedToRun = 10230
$kReplicationJobStateNoMonitoringEvents = 10231
$kReplicationJobStateSucceeded = 10232
$kReplicationJobStateFailed = 10233
$kReplicationJobStateFinishedSuccessfully = 10234
$kReplicationJobStateFinishedWithError = 10235

$kReplicationJobStateEventId = 10230 # This event is generated by Dynamics Server

### IISAppPoolStatus
$kIISAppPoolStatusStartedToRun = 10300
$kIISAppPoolStatusInetsrvNotExist = 10301
$kIISAppPoolStatusAppCmdDoesntExist = 10302
$kIISAppPoolStatusNoAppPoolName = 10303
$kIISAppPoolStatusAppcmdExitedWithError = 10304
$kIISAppPoolStatusUnexpectedAppcmdOutput = 10305
$kIISAppPoolStatusLogBagContent = 10306
$kIISAppPoolStatusFinishedSuccessfully = 10307
$kIISAppPoolStatusExitedWithError = 10308

### ConnectionToChannelDbState
$kConnectionToChannelDbStateStartedToRun = 10310
$kConnectionToChannelDbStateSearchingSuccessEvents = 10311
$kConnectionToChannelDbStateSearchingErrorEvents = 10312
$kConnectionToChannelDbStateNoMonitoringEvents = 10313
$kConnectionToChannelDbStateSuccess = 10314
$kConnectionToChannelDbStateFailed = 10315
$kConnectionToChannelDbStateFinishedSuccessfully = 10316
$kConnectionToChannelDbStateFinishedWithError = 10317

### HardwareStationSmokeTest
$kHardwareStationSmokeTestStartedToRun = 10320
$kHardwareStationSmokeTestFinishedSuccessfully = 10321
$kHardwareStationSmokeTestFinishedWithError = 10322

### ChangeTraceLevelInAppConfig
$kChangeTraceLevelInAppConfigStartedToRun = 10400
$kChangeTraceLevelInAppConfigFinishedSuccessfully = 10401
$kChangeTraceLevelInAppConfigFinishedWithError = 10402
$kChangeTraceLevelInAppConfigFileSaved = 10403
$kChangeTraceLevelInAppConfigFileUnchanged = 10404
$kChangeTraceLevelInAppConfigFileParameterCheckError = 10405

### ChangeSharePointTracingLevel
$kChangeSharePointTracingLevelStartedToRun = 10600
$kChangeSharePointTracingLevelFinishedSuccessfully = 10601
$kChangeSharePointTracingLevelFinishedWithError = 10602
$kChangeSharePointTracingLevelParameterCheckError = 10603

### EnterprisePosDiscovery
$kEnterprisePosDiscoveryStartedToRun = 10700
$kEnterprisePosDiscoveryFinishedSuccessfully = 10701
$kEnterprisePosDiscoveryFinishedWithError = 10702
$kNoEnterprisePosDiscoveryDataFound = 10703
$kEnterprisePosDiscoveryEvent = 10704

### EnterprisePosOfflineDiscovery
$kRetailPosOfflineServiceDiscoveryStartedToRun = 10800
$kNoRetailPosOfflineServiceDiscoveryDataFound = 10801
$kRetailPosOfflineServiceDiscoveryFinishedSuccessfully = 10802
$kRetailPosOfflineServiceDiscoveryRootKeyFound = 10803
$kRetailPosOfflineServiceDiscoveryNotUsedByPos = 10804
$kRetailPosOfflineServiceDiscoveryFinishedSuccessfully = 10805
$kNoRetailPosOfflineServiceAdditionalDiscoveryDataFound = 10806
$kRetailPosOfflineServiceDiscoveryFinishedSuccessfully = 10807
$kRetailPosOfflineServiceDiscoveryFinishedWithError = 10808

### StartAppPool
$kStartAppPoolStartedToRun = 10900
$kStartAppPoolFinishedSuccessfully = 10901
$kStartAppPoolFinishedWithError = 10902

### CertificateStatus
$kCertificateStatusStartedToRun = 10910
$kCertificateStatusNonExistingCertificate = 10911
$kCertificateStatusLogBagContent = 10912
$kCertificateStatusFinishedSuccessfully = 10913
$kCertificateStatusExitedWithError = 10914

### SetDiscoveryTimeFrame
$kSetDiscoveryTimeFrameStartedToRun = 10920
$kSetDiscoveryTimeFrameFinishedSuccessfully = 10921
$kSetDiscoveryTimeFrameFinishedWithError = 10922

## Functions
### Function tests if logging is enabled
function Test-LoggingEnabled
{
(Get-ItemProperty -Path $LoggingAbilityItemPath -ErrorAction SilentlyContinue).EnableMonitoringScriptLogging -eq "Enabled"
}

## Constants
$LoggingAbilityItemPath = "HKLM:\SOFTWARE\Microsoft\Dynamics\6.0"
$LoggingAbilityItemPropertyName = "EnableMonitoringScriptLogging"

$kLogWidth = 200 # characters
$kLogName = "Application"
$kLogSourceName = "Microsoft Dynamics AX Retail Monitoring"
$kEnableLogging = Test-LoggingEnabled

# This is needed to mock the logger object
if ($logger -ne $null)
{
# $logger object is initialized with the MS.Dynamics.Test.Retail.Test.Monitoring.Mocks.Logger object
$logger.LogName = $kLogName;
$logger.LogSourceName = $kLogSourceName;
$logger.ScriptName = $kScriptName;
}
else
{
# this means that object $logger is not initialized
## Create logger
$logger = New-Object -TypeName System.Management.Automation.PSObject

### Add logger properties
$logger | Add-Member -MemberType ScriptProperty -Name LogName -Value { $kLogName }
$logger | Add-Member -MemberType ScriptProperty -Name LogSourceName -Value { $kLogSourceName }
$logger | Add-Member -MemberType ScriptProperty -Name ScriptName -Value { $kScriptName }
$logger | Add-Member -MemberType ScriptProperty -Name ShouldWriteToEventLog -Value { $kEnableLogging }

### Add logger methods
$logger | Add-Member -MemberType ScriptMethod -Name LogInfo -Value {
param($eventId, $message)
if ($This.ShouldWriteToEventLog)
{
try
{
Write-EventLog -LogName $This.LogName -Source $This.LogSourceName -EntryType Information -EventId $eventId -Message ($This.ScriptName + " : " + $message) -ErrorAction Stop
}
catch
{
try
{
$scomApi.LogScriptEvent($This.ScriptName, $eventId, 0, "{0}" -f $message)
}
catch
{
}
}
}
}

$logger | Add-Member -MemberType ScriptMethod -Name LogError -Value {
param($eventId, $message)
try
{
Write-EventLog -LogName $This.LogName -Source $This.LogSourceName -EntryType Error -EventId $eventId -Message ($This.ScriptName + " : " + $message) -ErrorAction Stop
}
catch
{
try
{
$scomApi.LogScriptEvent($This.ScriptName, $eventId, 2, "{0}" -f $message)
}
catch
{
}
}
}

$logger | Add-Member -MemberType ScriptMethod -Name LogScriptExecutionSucceeded -Value {
param($eventId)
$This.LogInfo($eventId, "Script execution ended successfully")
}

$logger | Add-Member -MemberType ScriptMethod -Name LogScriptExecFailed -Value {
param($eventId, $error)
$This.LogError($eventId, "Script executed with errors :`n" + ($error | Out-String -Width $kLogWidth))
}

$logger | Add-Member -MemberType ScriptMethod -Name LogScriptExecFailedWithDefaultError -Value {
param($eventId)
$This.LogError($eventId, "Script executed with errors :`n" + ($Global:Error | Out-String -Width $kLogWidth))
}
}

#ScomApi.psm1#

## Create SCOM Api Object
# needed for mocking
if ($scomApi -ne $null)
{
# scomApi is created by wrapper test case
}
else
{
$scomApi = New-Object -ComObject 'MOM.ScriptAPI' -ErrorAction SilentlyContinue
if ($scomApi -eq $null) {
return $null
}
}

#EventLogHelper.psm1#
Function Get-InfoEvent()
{
param(
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$LogName,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$Source,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$EventId,
[Parameter(Mandatory=$true)]
[TimeSpan]$TimeFrame,
[Parameter(Mandatory=$false)]
[string]$MessagePrefix
)

$xmlFilter = Generate-WinEventXmlFilter -LogName $LogName -Source $Source -EventId $EventId -TimeFrameInSeconds $TimeFrame.TotalSeconds -Level "Information"

if ($PSBoundParameters.ContainsKey("MessagePrefix"))
{
Get-WinEvent -FilterXML $xmlFilter -ErrorAction SilentlyContinue | Where-Object { (Get-EventMessage -Event $_).StartsWith($MessagePrefix); $_ } | Write-Output
}
else
{
Get-WinEvent -FilterXML $xmlFilter -ErrorAction SilentlyContinue | Write-Output
}
}

# Function returns the last information event from the Application log from specified source with specific event id in the last N minutes
# which starts from specified prefix
Function Get-LastInfoEventInApplicationLog()
{
param(
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$Source,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$EventId,
[Parameter(Mandatory=$true)]
[int]$TimeFrameInSeconds,
[Parameter(Mandatory=$false)]
[string]$MessagePrefix
)

$xmlFilter = Generate-WinEventXmlFilter -Source $Source -EventId $EventId -TimeFrameInSeconds $TimeFrameInSeconds -Level "Information"

$events = Get-WinEvent -FilterXML $xmlFilter -ErrorAction SilentlyContinue

# if no events, then return $null
if (!$events) {
return $null
}
# according to the official docs, by default, events are returned in newest-first order, so there is no reason to order them.
foreach ($event in $events) {
if ((Get-EventMessage -Event $event).StartsWith($MessagePrefix)) {
return $event
}
}
return $null
}

# Function returns a string that can used as FilterXML parameter for Get-WinEvent cmdlet
Function Generate-WinEventXmlFilter
{
param(
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$Source,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string]$EventId,
[Parameter(Mandatory=$true)]
[int]$TimeFrameInSeconds,
[ValidateSet("Information", "Error")]
[string]$Level,
[Parameter(Mandatory=$false)]
[string]$LogName="Application"
)
if ($Level -eq "Information")
{
$levelCriteria = "Level=4 or Level=0"
}
elseif ($Level -eq "Error")
{
$levelCriteria = "Level=2"
}

$xmlFilter = `
"&lt;QueryList&gt;
&lt;Query Id=`"0`" Path=`"$LogName`"&gt;
&lt;Select Path=`"$LogName`"&gt;*[System[Provider[@Name='{0}'] and ({3}) and (EventID={1}) and TimeCreated[timediff(@SystemTime) &amp;lt;= {2}]]]&lt;/Select&gt;
&lt;/Query&gt;
&lt;/QueryList&gt;" -f $Source, $EventId, ($TimeFrameInSeconds * 1000), $levelCriteria

return $xmlFilter
}

Function Get-EventMessage()
{
[CmdletBinding()]
param([Parameter(ValueFromPipeline=$True)]$Event)
process
{
return ([xml]$Event.ToXml()).Event.EventData.Data.ToString()
}
}

#RegistryHelper.psm1#

$kDynamicsRegistryKey = "HKLM:\SOFTWARE\Microsoft\Dynamics\6.0"
$kTimeFramePropertySuffix = 'TimeFrameInSeconds'
$kDefaultTimeFrameValue = [int] 86400

Function Set-DiscoveryTimeFrame
{
param(
[Parameter(Mandatory=$true)]
[string]$DiscoveryName,
[Parameter(Mandatory=$true)]
[int]$TimeFrameInSeconds
)

if (-not (Test-Path $kDynamicsRegistryKey -ErrorAction Stop))
{
[void](New-Item -Path $kDynamicsRegistryKey -Force -ErrorAction Stop)
}
[void](New-ItemProperty -Force -ErrorAction Stop `
-Path $kDynamicsRegistryKey `
-Name ($DiscoveryName + $kTimeFramePropertySuffix) `
-PropertyType 'DWord' `
-Value $TimeFrameInSeconds)
}

Function Get-DiscoveryTimeFrame
{
param(
[Parameter(Mandatory=$true)]
[string]$DiscoveryName
)

$timeFrameInSeconds = (Get-ItemProperty -Path $kDynamicsRegistryKey -ErrorAction SilentlyContinue).($DiscoveryName + $kTimeFramePropertySuffix)
if ($timeFrameInSeconds)
{
return [int]$timeFrameInSeconds
}
else
{
return $kDefaultTimeFrameValue
}
}

$kRowDelimiter = "`n";
$kMessagePrefix = [string]::empty
$kColDelimiter = "::"
$RetailPosOfflineServiceSourceName = "Microsoft Dynamics AX Retail Monitoring : Retail POS Offline Sync Service"

$EnterprisePosOfflineSyncServiceRootKeyPath = "Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Dynamics\6.0\Retail POS Offline Sync Service"

if (${env:ProgramFiles(x86)} -ne $null)
{
$EnterprisePosOfflineSyncServiceRootKeyPath = "Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Dynamics\6.0\Retail POS Offline Sync Service"
}

# Run Discovery Script
$logger.LogInfo($kRetailPosOfflineServiceDiscoveryStartedToRun, ("Running on machine {0}. Element: {1} Target: {2}" -f $computerName, $element, $target))

try {
$discoveryData = $scomApi.CreateDiscoveryData(0, $element, $target)

if (!(Test-Path $EnterprisePosOfflineSyncServiceRootKeyPath)) {
$logger.LogInfo($kNoRetailPosOfflineServiceDiscoveryDataFound, ("Root key {0} not found on computer {1}" -f $EnterprisePosOfflineSyncServiceRootKeyPath, $computerName))

$logger.LogScriptExecutionSucceeded($kRetailPosOfflineServiceDiscoveryFinishedSuccessfully)

return $discoveryData
}

$logger.LogInfo($kRetailPosOfflineServiceDiscoveryRootKeyFound, ("Found root key {0}" -f $EnterprisePosOfflineSyncServiceRootKey))

$enterprisePosOfflineSyncServiceRootKey = Get-Item $EnterprisePosOfflineSyncServiceRootKeyPath

$instance = $discoveryData.CreateClassInstance("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']$")

$storeId = [string]($enterprisePosOfflineSyncServiceRootKey.GetValue("StoreID", [string]::Empty))
$registerId = [string]($enterprisePosOfflineSyncServiceRootKey.GetValue("RegisterID", [string]::Empty))
$sDataAreaId = [string]($enterprisePosOfflineSyncServiceRootKey.GetValue("DataAreaID", [string]::Empty))

if ([string]::IsNullOrEmpty($storeId) -or [string]::IsNullOrEmpty($registerId) -or [string]::IsNullOrEmpty($sDataAreaId))
{
$logger.LogInfo($kRetailPosOfflineServiceDiscoveryNotUsedByPos, "Retail POS Offline Sync Service was not configured to be used in Retail POS")
$logger.LogScriptExecutionSucceeded($kRetailPosOfflineServiceDiscoveryFinishedSuccessfully)
return $discoveryData
}

$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/StoreID$", $storeId)
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/RegisterID$", $registerId)
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/DataAreaID$", $sDataAreaId)

$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/StoreServerName$", [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("StoreServerName", [string]::Empty))
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/StoreDatabaseName$", [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("StoreDatabaseName", [string]::Empty))
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/OfflineServerName$", [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("OfflineServerName", [string]::Empty))
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/OfflineDatabaseName$", [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("OfflineDatabaseName", [string]::Empty))

# This value has to be present after install
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/InstallationDir$", [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("InstallationDir"))

# This value has to be present after install
$serviceName = [string]$enterprisePosOfflineSyncServiceRootKey.GetValue("ServiceName")
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/ServiceName$", $serviceName)

$serviceUserAccount = $(Get-WmiObject "Win32_Service" -Filter "Name='$serviceName'").StartName
$instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/ServiceUserAccount$", $serviceUserAccount)

$TimeFrameInSeconds = Get-DiscoveryTimeFrame -DiscoveryName "EnterprisePosOfflineServiceDiscovery"

# Additional Discovery properties logged when the service runs
$event = Get-LastInfoEventInApplicationLog -Source "$RetailPosOfflineServiceSourceName" -EventId $kRetailPosOfflineServiceDiscoveryNotUsedByPos -TimeFrameInSeconds $TimeFrameInSeconds -MessagePrefix "$kMessagePrefix"

if ($event -ne $null) {

$message = (Get-EventMessage -Event $event).Substring($kMessagePrefix.Length)

foreach ($record in ($message -split $kRowDelimiter)) {

$fields = $record -Split $kColDelimiter

if ($fields.Count -ne 2)
{
continue
}

$key = $fields[0]
$value = $fields[1]

switch ($key)
{
"SyncInterval" { $instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/SyncInterval$", $value); break; }

"MemoryDataCacheSizeKB" { $instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/MemoryDataCacheSizeKB$", $value) ; break; }

"SyncInParallel" { $instance.AddProperty("$MPElement[Name='Microsoft.Dynamics.Retail.AX2012.R2.FP.Base.Class.RetailPosOfflineService']/SyncInParallel$", $value) ; break; }
}
}
}
else
{
$logger.LogInfo($kNoRetailPosOfflineServiceAdditionalDiscoveryDataFound, ("Couldn't find any events during last {0} seconds on computer {1}" -f $TimeFrameInSeconds, $computerName))
}

$instance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $computerName)
$instance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $computerName)

$discoveryData.AddInstance($instance)

$logger.LogScriptExecutionSucceeded($kRetailPosOfflineServiceDiscoveryFinishedSuccessfully)

} catch {
$discoveryData = $null
$logger.LogScriptExecFailedWithDefaultError($kRetailPosOfflineServiceDiscoveryFinishedWithError)
}
return $discoveryData
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>Target</Name>
<Value>$Target/Id$</Value>
</Parameter>
<Parameter>
<Name>Element</Name>
<Value>$MPElement$</Value>
</Parameter>
<Parameter>
<Name>ComputerName</Name>
<Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Parameter>
</Parameters>
<TimeoutSeconds>60</TimeoutSeconds>
</DataSource>
</Discovery>