diff --git a/.gitignore b/.gitignore
index a5d1fca..b4ed384 100644
--- a/.gitignore
+++ b/.gitignore
@@ -195,3 +195,5 @@ ModelManifest.xml
/Atea.Windows.Server.Monitoring/AteaST.snk
/Atea.Windows.Service.Monitoring/AteaST.snk
/AteaST.snk
+VisualStudioAuthoringConsole_x64.msi
+_Scripts/VisualStudioAuthoringConsole_x64.msi
diff --git a/Atea.Windows.File.Monitoring/Atea.Windows.File.Monitoring.mpproj b/Atea.Windows.File.Monitoring/Atea.Windows.File.Monitoring.mpproj
index 68f4001..8d76d40 100644
--- a/Atea.Windows.File.Monitoring/Atea.Windows.File.Monitoring.mpproj
+++ b/Atea.Windows.File.Monitoring/Atea.Windows.File.Monitoring.mpproj
@@ -55,9 +55,16 @@
Code
+
+ Code
+
Code
+
+ Code
+ HealthModel\Monitors\FileAge.mptg
+
Code
@@ -67,6 +74,9 @@
Code
+
+ Code
+
Code
@@ -79,12 +89,27 @@
Code
+
+ Code
+
+
+ Code
+
Code
Code
+
+ Code
+
+
+ Code
+
+
+ Code
+
@@ -106,9 +131,16 @@
-
+
+
+
+
+
+ Content
+ FragmentGenerator
+
\ No newline at end of file
diff --git a/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileAgeFolderDiscovery.mpx b/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileAgeFolderDiscovery.mpx
new file mode 100644
index 0000000..8582554
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileAgeFolderDiscovery.mpx
@@ -0,0 +1,27 @@
+
+
+
+
+ Discovery
+
+
+
+
+ $MPElement$
+ $Target/Id$
+ $Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$
+ 14400
+
+
+
+
+
+
+
+
+ Atea FileAge Folder Discovery
+
+
+
+
+
\ No newline at end of file
diff --git a/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileMonitoringSeedDiscovery.mpx b/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileMonitoringSeedDiscovery.mpx
index 1faab85..66c4222 100644
--- a/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileMonitoringSeedDiscovery.mpx
+++ b/Atea.Windows.File.Monitoring/HealthModel/Discoveries/FileMonitoringSeedDiscovery.mpx
@@ -15,6 +15,12 @@
0
0
+
+ FAgeKeyExist
+ SOFTWARE\Atea\FileAgeMonitoring
+ 0
+ 0
+
14400
$MPElement[Name="Atea.Windows.File.Monitoring.Seed"]$
@@ -27,15 +33,30 @@
-
-
- Values/FCKeyExist
-
- Equal
-
- true
-
-
+
+
+
+
+ Values/FCKeyExist
+
+ Equal
+
+ true
+
+
+
+
+
+
+ Values/FAgeKeyExist
+
+ Equal
+
+ true
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg b/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg
new file mode 100644
index 0000000..46aeefc
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg
@@ -0,0 +1,41 @@
+
+
+
+
+ Windows.File.FileAge.MonitorType
+ <TimeoutSeconds>300</TimeoutSeconds><IntervalSeconds>300</IntervalSeconds><FolderFriendlyName>$Target/Property[Type="Atea.Windows.File.FileAgeFolder"]/FriendlyName$</FolderFriendlyName><FileAgeAttribute>$Target/Property[Type="Atea.Windows.File.FileAgeFolder"]/FileAgeAttribute$</FileAgeAttribute>
+
+
+ Healthy
+ No Files Found
+ Healthy
+ Success
+
+
+ Error
+ Bad Files Found
+ Error
+ Error
+
+
+ Health!System.Health.AvailabilityState
+ Public
+ FileAgeMonitor
+ File Age Monitor
+ This monitor will look for files in a folder, recursively if configured so, and alert if one of more files are found.
+ Atea.Windows.File.FileAgeFolder
+ true
+ AvailabilityHealth
+ true
+ Normal
+ true
+ Error
+ Normal
+ MatchMonitorHealth
+ Files with bad timestamp found
+ $Data/Context/Property[@Name="Summary"]$
+ false
+
+
+
+
\ No newline at end of file
diff --git a/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg.mpx b/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg.mpx
new file mode 100644
index 0000000..62145de
Binary files /dev/null and b/Atea.Windows.File.Monitoring/HealthModel/Monitors/FileAge.mptg.mpx differ
diff --git a/Atea.Windows.File.Monitoring/Scripts/AteaFCTPSPropertyBag.ps1 b/Atea.Windows.File.Monitoring/Scripts/AteaFCTPSPropertyBag.ps1
deleted file mode 100644
index 5612c44..0000000
--- a/Atea.Windows.File.Monitoring/Scripts/AteaFCTPSPropertyBag.ps1
+++ /dev/null
@@ -1,69 +0,0 @@
-# Begin with getting all the subkeys
-# http://technet.microsoft.com/en-us/library/ff730937.aspx
-# http://powershell.com/cs/blogs/tips/archive/2009/12/03/dynamically-create-script-blocks.aspx
-# http://technet.microsoft.com/sv-se/library/ee176852(en-us).aspx
-
-$RegistryPath = "hklm:\Software\Atea\FileCreation\"
-$EventLogSourceName = "Atea FCT Monitor"
-$SubKeys = Get-ChildItem $RegistryPath
-$OpsmgrAPI = New-Object -ComObject "MOM.ScriptAPI"
-if (![System.Diagnostics.EventLog]::SourceExists($EventLogSourceName))
-{
- New-EventLog -Source $EventLogSourceName -logname "Application"
-}
-ForEach ($SubKey in $SubKeys)
-{
- $FriendlyName = ($SubKey.Name.Substring($SubKey.Name.LastIndexOfAny("\")+1))
- $FolderPath = $SubKey.GetValue("FolderPath")
- $Recursive = $SubKey.GetValue("Recursive")
- $FilePattern = $SubKey.GetValue("FilePattern")
- $AgeInMinutes = $SubKey.GetValue("AgeInMinutes")
- $Operator = $SubKey.GetValue("Operator")
-
- if (($FolderPath -ne $null) -and ($Recursive -ne $null) -and ($FilePattern -ne $null) -and ($AgeInMinutes -ne $null) -and ($Operator -ne $null))
- {
- $Operator = $Operator.Trim()
-
- switch ($Operator)
- {
- "<" {$Operator = "-lt"}
- "<=" {$Operator = "-le"}
- ">" {$Operator = "-gt"}
- ">=" {$Operator = "-ge"}
- default {$Operator = "-gt"}
- }
-
- if ($Recursive.Trim() -eq "false")
- {
- $Recursive = ""
- } else {
- $Recursive = "-Recurse "
- }
-
- $command = "Get-ChildItem $FolderPath $Recursive| where {(`$_.Name -like '$FilePattern') -and ((((Get-Date) - `$_.CreationTime).TotalMinutes) $Operator $AgeInMinutes)}"
- $ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock($command)
- #$command
- $Files = @(Invoke-Command -ScriptBlock $ScriptBlock)
- If ($Files.Count -gt 0)
- {
- ForEach ($File in $Files)
- {
- $FileName = $File.Name
- $FileFullname = $File.FullName
- $FileCreationTime = $File.CreationTime
- $FileAgeMinutes = [math]::Round(((Get-Date) - $FileCreationTime).TotalMinutes,0)
-
- #Add values to propertybag for monitoring
- $propertyBag = $OpsmgrAPI.CreatePropertyBag()
- $propertyBag.AddValue("FileName",$FileName)
- $propertyBag.AddValue("FileFullname",$FileFullname)
- $propertyBag.AddValue("FileCreationTime",$FileCreationTime)
- $propertyBag.AddValue("FileAgeMinutes",$FileAgeMinutes)
- $propertyBag.AddValue("FolderFriendlyName",$FriendlyName)
-
- $propertyBag
- Write-EventLog -LogName "Application" -Source $EventLogSourceName -EventID "400" -Message "Filename: $FileName `nFilepath: $FileFullname `nFileAge: $FileAgeMinutes minutes`nFileCreationTime: $FileCreationTime `n`nFolder FriendlyName=$FriendlyName"
- }
- }
- }
-}
diff --git a/Atea.Windows.File.Monitoring/Scripts/AteaFileCreationTimePoSHDiscovery.ps1 b/Atea.Windows.File.Monitoring/Scripts/AteaFileCreationTimePoSHDiscovery.ps1
index 5077f7a..0c4b3d8 100644
--- a/Atea.Windows.File.Monitoring/Scripts/AteaFileCreationTimePoSHDiscovery.ps1
+++ b/Atea.Windows.File.Monitoring/Scripts/AteaFileCreationTimePoSHDiscovery.ps1
@@ -7,9 +7,9 @@ param([string]$sourceId, [string]$managedEntityId, [string]$computerName)
$RegistryPath = "hklm:\Software\Atea\FileCreationTime\"
$SubKeys = Get-ChildItem $RegistryPath
-$OpsmgrAPI = New-Object -ComObject "MOM.ScriptAPI"
-#$OpsmgrAPI.LogScriptEvent("AteaFilCreationPoSHDiscovery.ps1", 242, 4, "Running File Creation Folder discovery with parameters $sourceId, $managedEntityId, $computerName")
-$discoveryData = $OpsmgrAPI.CreateDiscoveryData(0, $sourceId, $managedEntityId)
+$omApi = New-Object -ComObject "MOM.ScriptAPI"
+#$omApi.LogScriptEvent("AteaFilCreationPoSHDiscovery.ps1", 242, 4, "Running File Creation Folder discovery with parameters $sourceId, $managedEntityId, $computerName")
+$discoveryData = $omApi.CreateDiscoveryData(0, $sourceId, $managedEntityId)
ForEach ($SubKey in $SubKeys)
{
$FriendlyName = ($SubKey.Name.Substring($SubKey.Name.LastIndexOfAny("\")+1))
@@ -18,12 +18,12 @@ ForEach ($SubKey in $SubKeys)
$FilePattern = $SubKey.GetValue("FilePattern")
$AgeInMinutes = $SubKey.GetValue("AgeInMinutes")
$Operator = $SubKey.GetValue("Operator")
-
-
+
+
if (($FolderPath -ne $null) -and ($Recursive -ne $null) -and ($FilePattern -ne $null) -and ($AgeInMinutes -ne $null) -and ($Operator -ne $null))
{
$Operator = $Operator.Trim()
-
+
#Add values to property bag for Discovery
$discoveryInstance = $discoveryData.CreateClassInstance("$MPElement[Name='Atea.Windows.File.FileCreationTimeFolder']$")
$discoveryInstance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $computerName)
diff --git a/Atea.Windows.File.Monitoring/Scripts/FileAgePB.ps1 b/Atea.Windows.File.Monitoring/Scripts/FileAgePB.ps1
new file mode 100644
index 0000000..aa77e25
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/Scripts/FileAgePB.ps1
@@ -0,0 +1,107 @@
+# Begin with getting all the subkeys
+# http://technet.microsoft.com/en-us/library/ff730937.aspx
+# http://powershell.com/cs/blogs/tips/archive/2009/12/03/dynamically-create-script-blocks.aspx
+# http://technet.microsoft.com/sv-se/library/ee176852(en-us).aspx
+
+[CmdletBinding()]
+Param(
+ [ValidateSet("CreationTime","LastWriteTime","LastAccessTime")]
+ [Parameter(Mandatory=$true)]
+ [string] $FileAgeAttribute
+)
+
+$RegistryPath = "hklm:\Software\Atea\FileAgeMonitoring\"
+$EventLogSourceName = "Atea FileAge Monitor"
+$omApi = New-Object -ComObject "MOM.ScriptAPI"
+if (![System.Diagnostics.EventLog]::SourceExists($EventLogSourceName)) {
+ New-EventLog -Source $EventLogSourceName -logname "Application"
+}
+
+if (Test-Path -Path $RegistryPath) {
+ # Yes, we can read from $RegistryPath
+ $SubKeys = Get-ChildItem $RegistryPath
+
+ if ($SubKeys -ne $null) {
+ # Found configuration keys, processing folders
+ ForEach ($SubKey in $SubKeys) {
+ $FriendlyName = ($SubKey.Name.Substring($SubKey.Name.LastIndexOfAny("\")+1))
+ $FolderPath = $SubKey.GetValue("FolderPath")
+ $Recursive = $SubKey.GetValue("Recursive")
+ $FilePattern = $SubKey.GetValue("FilePattern")
+ $AgeInMinutes = $SubKey.GetValue("AgeInMinutes")
+ $Operator = $SubKey.GetValue("Operator")
+ # $AgeAttribute = $SubKey.GetValue("FileAgeAttribute") # Don't know if I really need this
+
+ if (($FolderPath -ne $null) -and ($Recursive -ne $null) -and ($FilePattern -ne $null) -and ($AgeInMinutes -ne $null) -and ($Operator -ne $null)) {
+ $Operator = $Operator.Trim()
+
+ switch ($Operator)
+ {
+ "<" {$Operator = "-lt"}
+ "<=" {$Operator = "-le"}
+ ">" {$Operator = "-gt"}
+ ">=" {$Operator = "-ge"}
+ default {$Operator = "-gt"}
+ }
+
+ $summaryMessage = "File Age Monitor on '$FriendlyName', looking for '$FilePattern' where $FileAgeAttribute $Operator $AgeInMinutes in $FolderPath"
+
+ if ($Recursive.Trim() -eq "false")
+ {
+ $Recursive = ""
+ $summaryMessage += "`n`n"
+ } else {
+ $Recursive = "-Recurse "
+ $summaryMessage += ", Recursive`n`n"
+ }
+
+ $command = "Get-ChildItem $FolderPath $Recursive -Attributes !Directory | where {(`$_.Name -like '$FilePattern') -and ((((Get-Date) - `$_.$FileAgeAttribute).TotalMinutes) $Operator $AgeInMinutes)}"
+ $ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock($command)
+ $Files = @(Invoke-Command -ScriptBlock $ScriptBlock)
+ if ($Files.Count -gt 0) {
+ $summaryMessage += "Found $($Files.Count) matching files:`n"
+ #$summaryMessage += "File Name`tFile Path`t`tAge (minutes)`tTimeStamp`n"
+ ForEach ($File in $Files)
+ {
+ $FileName = $File.Name
+ $FileFullname = $File.FullName
+ switch ($FileAgeAttribute) {
+ "CreationTime" {$FileDateTime = $File.CreationTime}
+ "LastWriteTime" {$FileDateTime = $File.LastWriteTime}
+ "LastAccessTime" {$FileDateTime = $File.LastAccessTime}
+ }
+ $FileAgeMinutes = [math]::Round(((Get-Date) - $FileDateTime).TotalMinutes,0)
+ $summaryMessage += "$FileName`n`tMinutes since $($FileAgeAttribute): $FileAgeMinutes`n`tTimestamp: $($FileDateTime -f "o")`n`tFile Path: $FileFullName`n`n"
+ }
+ #We have old files, and a message. Build the property bag
+ $propertyBag = $omApi.CreatePropertyBag()
+ $propertyBag.AddValue("FolderFriendlyName",$FriendlyName)
+ $propertyBag.AddValue("Summary",$summaryMessage)
+ $propertyBag.AddValue("FileCount",$Files.Count)
+
+ $propertyBag
+ Write-EventLog -LogName "Application" -Source $EventLogSourceName -EventID "400" -Message $summaryMessage -EntryType Information -Category 0
+
+ } else {
+ # No matching files found
+ $propertyBag = $omApi.CreatePropertyBag()
+ $propertyBag.AddValue("FolderFriendlyName",$FriendlyName)
+ $propertyBag.AddValue("Summary",$summaryMessage)
+ $propertyBag.AddValue("FileCount",$Files.Count)
+
+ $propertyBag
+ }
+ }
+ }
+ } else {
+ # Registry does not contain any configured File Age Monitoring
+ # or we don't have access to read the keys
+ $propertyBag = $omApi.CreatePropertyBag()
+ $propertyBag
+ }
+} else {
+ #Nope, not able to read from the registry path
+ Write-EventLog -LogName "Application" -Source $EventLogSourceName -EventID "404" -Message "$RegistryPath is not found on this system, unable to read file age monitoring configuration.`n`nReturning an empty property bag." -EntryType Error -Category 0
+ $propertyBag = $omApi.CreatePropertyBag()
+ $propertyBag
+}
\ No newline at end of file
diff --git a/Atea.Windows.File.Monitoring/Scripts/FileAgePoSHDiscovery.ps1 b/Atea.Windows.File.Monitoring/Scripts/FileAgePoSHDiscovery.ps1
new file mode 100644
index 0000000..baae1f6
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/Scripts/FileAgePoSHDiscovery.ps1
@@ -0,0 +1,53 @@
+# Begin with getting all the subkeys
+# http://technet.microsoft.com/en-us/library/ff730937.aspx
+# http://powershell.com/cs/blogs/tips/archive/2009/12/03/dynamically-create-script-blocks.aspx
+# http://technet.microsoft.com/sv-se/library/ee176852(en-us).aspx
+
+param([string]$sourceId, [string]$managedEntityId, [string]$computerName)
+
+$EventLogSourceName = "Atea FileAge Monitor"
+$eventlogMessage = "Running FileAgeFolder discovery.`n"
+$eventlogMessage += "Params:`n`tsourceId=$sourceId`n`tmanagedEntityId=$managedEntityId`n`tcomputerName=$computerName`n`n"
+if (![System.Diagnostics.EventLog]::SourceExists($EventLogSourceName)) {
+ New-EventLog -Source $EventLogSourceName -logname "Application"
+}
+
+$RegistryPath = "hklm:\Software\Atea\FileAgeMonitoring\"
+$omApi = New-Object -ComObject "MOM.ScriptAPI"
+$discoveryData = $omApi.CreateDiscoveryData(0, $sourceId, $managedEntityId)
+if (Test-Path -Path $RegistryPath) {
+ # Registry path is accessible
+ $SubKeys = Get-ChildItem $RegistryPath
+ ForEach ($SubKey in $SubKeys)
+ {
+ $FriendlyName = ($SubKey.Name.Substring($SubKey.Name.LastIndexOfAny("\")+1))
+ $FolderPath = $SubKey.GetValue("FolderPath")
+ $Recursive = $SubKey.GetValue("Recursive")
+ $FilePattern = $SubKey.GetValue("FilePattern")
+ $AgeInMinutes = $SubKey.GetValue("AgeInMinutes")
+ $Operator = $SubKey.GetValue("Operator")
+ $FileAgeAttribute = $SubKey.GetValue("FileAgeAttribute")
+
+
+ if (($FolderPath -ne $null) -and ($Recursive -ne $null) -and ($FilePattern -ne $null) -and ($AgeInMinutes -ne $null) -and ($Operator -ne $null) -and ($FileAgeAttribute -ne $null))
+ {
+ $Operator = $Operator.Trim()
+
+ #Add values to property bag for Discovery
+ $discoveryInstance = $discoveryData.CreateClassInstance("$MPElement[Name='Atea.Windows.File.FileAgeFolder']$")
+ $discoveryInstance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $computerName)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/FriendlyName$",$FriendlyName)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/FolderPath$",$FolderPath)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/Recursive$",$Recursive)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/FilePattern$",$FilePattern)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/AgeInMinutes$",$AgeInMinutes)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/Operator$",$Operator)
+ $discoveryInstance.AddProperty("$MPElement[Name='Atea.Windows.File.FileAgeFolder']/FileAgeAttribute$",$FileAgeAttribute)
+ $discoveryData.AddInstance($discoveryInstance)
+ $eventlogMessage += "- Added $($FriendlyName) to discovery data`n"
+ }
+ }
+}
+
+Write-EventLog -LogName "Application" -Source $EventLogSourceName -EventID "200" -Message "" -EntryType Information -Category 0
+$discoveryData
diff --git a/Atea.Windows.File.Monitoring/ServiceModel/Classes/FileAgeFolder.mpx b/Atea.Windows.File.Monitoring/ServiceModel/Classes/FileAgeFolder.mpx
new file mode 100644
index 0000000..4c33777
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/ServiceModel/Classes/FileAgeFolder.mpx
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Atea File Age Folder
+
+
+
+
+
+ Folder Path
+
+
+
+ Recursive Check
+
+
+
+
+
+ File Pattern
+
+
+
+ Age in Minutes
+
+
+
+ Operator
+
+
+
+ Friendly Name
+
+
+
+ File Age Attribute
+
+
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgeFolderDiscoveryDS.mpx b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgeFolderDiscoveryDS.mpx
new file mode 100644
index 0000000..a3c21a4
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgeFolderDiscoveryDS.mpx
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+ Health!System.Health.AlertSchema
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $Config/IntervalSeconds$
+
+
+
+
+
+ $Config/MPElement$
+ $Config/TargetID$
+ $Config/ComputerName$
+
+
+
+
+
+
+
+
+
+ System!System.Discovery.Data
+
+
+
+
+
+
+
+ Atea File Age Folder Discovery Data Source
+ This datasource provides the basic discovery data for the watched folders.
+
+
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgePropertyBagDS.mpx b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgePropertyBagDS.mpx
new file mode 100644
index 0000000..6df853f
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/DataSources/FileAgePropertyBagDS.mpx
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $Config/IntervalSeconds$
+
+
+
+
+
+ $Config/FileAgeAttribute$
+ $Config/TimeoutSeconds$
+
+
+
+
+
+ Property[@Name='FolderFriendlyName']
+
+ Equal
+
+ $Config/FolderFriendlyName$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ System!System.PropertyBagData
+
+
+
+
+
+
+
+ Atea Windows File - File Age PropertyBag Data Source
+
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgeFolderDiscoveryProbe.mpx b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgeFolderDiscoveryProbe.mpx
new file mode 100644
index 0000000..4828577
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgeFolderDiscoveryProbe.mpx
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ Windows!Microsoft.Windows.PowerShellSchema
+ System!System.ParamListSchema
+
+
+
+
+
+
+
+
+
+ FileAgePoSHDiscovery.ps1
+ $IncludeFileContent/Scripts/FileAgePoSHDiscovery.ps1$
+
+
+ sourceId
+ $Config/MPElement$
+
+
+ managedEntityId
+ $Config/TargetID$
+
+
+ ComputerName
+ $Config/ComputerName$
+
+
+ 300
+
+
+
+
+
+
+
+ System!System.Discovery.Data
+ System!System.TriggerData
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgePoSHProbe.mpx b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgePoSHProbe.mpx
new file mode 100644
index 0000000..509528b
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/FileAgePoSHProbe.mpx
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FileAgePB.ps1
+ $IncludeFileContent/Scripts/FileAgePB.ps1$
+
+
+
+ FileAgeAttribute
+ $Config/FileAgeAttribute$
+
+
+ $Config/TimeoutSeconds$
+
+
+
+
+
+
+
+ System!System.PropertyBagData
+ true
+
+
+
+
diff --git a/Atea.Windows.File.Monitoring/TypeLibrary/MonitorTypes/FileAgeMonitoryType.mpx b/Atea.Windows.File.Monitoring/TypeLibrary/MonitorTypes/FileAgeMonitoryType.mpx
new file mode 100644
index 0000000..2c6f7b7
--- /dev/null
+++ b/Atea.Windows.File.Monitoring/TypeLibrary/MonitorTypes/FileAgeMonitoryType.mpx
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $Config/TimeoutSeconds$
+ $Config/IntervalSeconds$
+ $Config/FolderFriendlyName$
+ $Config/FileAgeAttribute$
+
+
+ $Config/FileAgeAttribute$
+ $Config/TimeoutSeconds$
+
+
+
+
+
+ Property[@Name='FolderFriendlyName']
+
+ Equal
+
+ $Config/FolderFriendlyName$
+
+
+
+
+
+
+
+
+ Property[@Name='FileCount']
+
+ NotEqual
+
+ 0
+
+
+
+
+
+
+
+
+ Property[@Name='FileCount']
+
+ Equal
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Atea.Windows.Installer/Atea.Windows.Installer.vdproj b/Atea.Windows.Installer/Atea.Windows.Installer.vdproj
index a9ae84c..c33f0a8 100644
--- a/Atea.Windows.Installer/Atea.Windows.Installer.vdproj
+++ b/Atea.Windows.Installer/Atea.Windows.Installer.vdproj
@@ -11,6 +11,7 @@
"SccLocalPath" = "8:"
"SccAuxPath" = "8:"
"SccProvider" = "8:"
+"BackwardsCompatibleGUIDGeneration" = "8:TRUE"
"Hierarchy"
{
"Entry"
@@ -46,19 +47,19 @@
"Entry"
{
"MsmKey" = "8:_UNDEFINED"
- "OwnerKey" = "8:_53950D255F9649DC80B517E8902CA97A"
+ "OwnerKey" = "8:_C58F4C60AE9D4646B6B73E6E83A7F892"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_UNDEFINED"
- "OwnerKey" = "8:_C58F4C60AE9D4646B6B73E6E83A7F892"
+ "OwnerKey" = "8:_989F92A89DCC4C05A2671096BBB0BFB7"
"MsmSig" = "8:_UNDEFINED"
}
"Entry"
{
"MsmKey" = "8:_UNDEFINED"
- "OwnerKey" = "8:_989F92A89DCC4C05A2671096BBB0BFB7"
+ "OwnerKey" = "8:_53950D255F9649DC80B517E8902CA97A"
"MsmSig" = "8:_UNDEFINED"
}
}
@@ -79,6 +80,14 @@
"PrivateKeyFile" = "8:"
"TimeStampServer" = "8:"
"InstallerBootstrapper" = "3:2"
+ "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
+ {
+ "Enabled" = "11:TRUE"
+ "PromptEnabled" = "11:TRUE"
+ "PrerequisitesLocation" = "2:1"
+ "Url" = "8:"
+ "ComponentsUrl" = "8:"
+ }
}
"Release"
{
@@ -100,7 +109,7 @@
"Enabled" = "11:FALSE"
"PromptEnabled" = "11:TRUE"
"PrerequisitesLocation" = "2:1"
- "Url" = "8:"
+ "Url" = "8:https://github.com/stegenfeldt/Atea.Windows/raw/master/Released/Atea.Windows.Installer.msi"
"ComponentsUrl" = "8:"
"Items"
{
@@ -139,7 +148,7 @@
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
- "AssemblyAsmDisplayName" = "8:Atea.Windows.File.Monitoring, Version=1.0.3.2, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
+ "AssemblyAsmDisplayName" = "8:Atea.Windows.File.Monitoring, Version=1.0.3.51, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_4E738A19F12B461CB0E1656840A98197"
@@ -170,7 +179,7 @@
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
- "AssemblyAsmDisplayName" = "8:Atea.Windows.Service.Monitoring, Version=1.0.3.2, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
+ "AssemblyAsmDisplayName" = "8:Atea.Windows.Service.Monitoring, Version=1.0.3.20, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_53950D255F9649DC80B517E8902CA97A"
@@ -201,7 +210,7 @@
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
- "AssemblyAsmDisplayName" = "8:Atea.Windows.Library, Version=1.0.3.2, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
+ "AssemblyAsmDisplayName" = "8:Atea.Windows.Library, Version=1.0.3.8, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_989F92A89DCC4C05A2671096BBB0BFB7"
@@ -232,7 +241,7 @@
{
"AssemblyRegister" = "3:1"
"AssemblyIsInGAC" = "11:FALSE"
- "AssemblyAsmDisplayName" = "8:Atea.Windows.Server.Monitoring, Version=1.0.3.2, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
+ "AssemblyAsmDisplayName" = "8:Atea.Windows.Server.Monitoring, Version=1.0.3.7, Culture=neutral, PublicKeyToken=62373e1518b7f72f, processorArchitecture=MSIL"
"ScatterAssemblies"
{
"_C58F4C60AE9D4646B6B73E6E83A7F892"
@@ -354,7 +363,7 @@
"AspNetVersion" = "8:4.0.30319.0"
"RestartWWWService" = "11:FALSE"
"RemovePreviousVersions" = "11:TRUE"
- "DetectNewerInstalledVersion" = "11:TRUE"
+ "DetectNewerInstalledVersion" = "11:FALSE"
"InstallAllUsers" = "11:TRUE"
"ProductVersion" = "8:1.0.3"
"Manufacturer" = "8:Atea Sverige AB"
@@ -362,7 +371,7 @@
"ARPHELPLINK" = "8:https://github.com/stegenfeldt/Atea.Windows/issues"
"Title" = "8:Atea.Windows.Installer"
"Subject" = "8:"
- "ARPCONTACT" = "8:Samuel Tegenfledt - Atea Sverige AB"
+ "ARPCONTACT" = "8:Samuel Tegenfeldt - Atea Sverige AB"
"Keywords" = "8:OpsMgr, System Center, Management Pack"
"ARPCOMMENTS" = "8:"
"ARPURLINFOABOUT" = "8:"
diff --git a/Atea.Windows.Library/Atea.Windows.Library.mpproj b/Atea.Windows.Library/Atea.Windows.Library.mpproj
index 891c9de..22ce0e5 100644
--- a/Atea.Windows.Library/Atea.Windows.Library.mpproj
+++ b/Atea.Windows.Library/Atea.Windows.Library.mpproj
@@ -33,23 +33,23 @@
SC
- false
+ False
Windows
- false
+ False
Health
- false
+ False
System
- false
+ False
Visualization
- false
+ False
diff --git a/Atea.Windows.Service.Monitoring/Atea.Windows.Service.Monitoring.mpproj b/Atea.Windows.Service.Monitoring/Atea.Windows.Service.Monitoring.mpproj
index 9c8b433..331a06a 100644
--- a/Atea.Windows.Service.Monitoring/Atea.Windows.Service.Monitoring.mpproj
+++ b/Atea.Windows.Service.Monitoring/Atea.Windows.Service.Monitoring.mpproj
@@ -6,7 +6,7 @@
Atea.Windows.Service
Atea.Windows.Service.Monitoring
Atea.Windows.Service.Monitoring
- 1.0.3.0
+ 1.0.3.20
v7.0
OM
1.1.0.0
diff --git a/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg b/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg
index b04d58c..d65db84 100644
--- a/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg
+++ b/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg
@@ -23,7 +23,7 @@
Normal
Error
Failed to Recovery Service
- $Data/Property[@Name='EventDescription']$
+ $Data/EventDescription$
diff --git a/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg.mpx b/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg.mpx
index 68aefee..a2f6803 100644
Binary files a/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg.mpx and b/Atea.Windows.Service.Monitoring/HealthModel/Rules/AlertRules.mptg.mpx differ
diff --git a/Atea.Windows.Service.Monitoring/HealthModel/Tasks/Recoveries/ServiceStartRecoveryTask.mpx b/Atea.Windows.Service.Monitoring/HealthModel/Tasks/Recoveries/ServiceStartRecoveryTask.mpx
index 0e1d00c..6dc5b00 100644
--- a/Atea.Windows.Service.Monitoring/HealthModel/Tasks/Recoveries/ServiceStartRecoveryTask.mpx
+++ b/Atea.Windows.Service.Monitoring/HealthModel/Tasks/Recoveries/ServiceStartRecoveryTask.mpx
@@ -6,7 +6,7 @@
- start $Target/Property[Type='MSNL!Microsoft.SystemCenter.NTService']/ServiceName$
+ start "$Target/Property[Type='MSNL!Microsoft.SystemCenter.NTService']/ServiceName$"
300
true
diff --git a/Atea.Windows.Service.Monitoring/Scripts/AteaAutoSvcPBScript.vbs b/Atea.Windows.Service.Monitoring/Scripts/AteaAutoSvcPBScript.vbs
index 2f54d36..c04c533 100644
--- a/Atea.Windows.Service.Monitoring/Scripts/AteaAutoSvcPBScript.vbs
+++ b/Atea.Windows.Service.Monitoring/Scripts/AteaAutoSvcPBScript.vbs
@@ -39,62 +39,66 @@ If NOT IsNull(automaticServices) Then
' We got a "hit" on a service name configured in the registry
' Create the SCOM property bag instances and return them to SCOM
Set scomApi = CreateObject("MOM.ScriptAPI")
-
+
For Each automaticService In automaticServices
serviceName = automaticService.Name
' Add one property bag per service
LogEvent SCOM_DEBUG,SCOM_INFO,"Found automatic service: " & serviceName
- If Ubound(Filter(serviceExceptions, serviceName,True,1)) > -1 Then
- 'Got match, service shound be excluded from discovery
- LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to exclusion list: " & serviceName
- ElseIf Ubound(Filter(standardExclusions, serviceName,True,1)) > -1 Then
- 'Got match, service shound be excluded from discovery
- LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to standard exclusion list: " & serviceName
- ElseIf Ubound(Filter(xylemExclusions, serviceName,True,1)) > -1 Then
- 'Got match, service shound be excluded from discovery
- LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to Xylem exclusion list: " & serviceName
- Else
- ' No match, service is not in exclusion list.
- ' Process and add to property bag
- If Err.Number = 0 Then
- With automaticService
- Set scomPropertyBag = scomApi.CreatePropertyBag() ' Instance of a new property bag
-
- ' Start adding values to the propertybag
- Call scomPropertyBag.AddValue("Name",Cstr(.Name))
- Call scomPropertyBag.AddValue("DisplayName",Cstr(.DisplayName))
- If .Description <> vbNull Then
- Call scomPropertyBag.AddValue("Description",Cstr(.Description))
+ If Ubound(Filter(serviceExceptions, serviceName,True,1)) > -1 Then
+ 'Got match, service shound be excluded from discovery
+ LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to exclusion list: " & serviceName
+ ElseIf Ubound(Filter(standardExclusions, serviceName,True,1)) > -1 Then
+ 'Got match, service shound be excluded from discovery
+ LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to standard exclusion list: " & serviceName
+ ElseIf Ubound(Filter(xylemExclusions, serviceName,True,1)) > -1 Then
+ 'Got match, service shound be excluded from discovery
+ LogEvent SCOM_DEBUG,SCOM_INFO,"Service is ignored due to Xylem exclusion list: " & serviceName
+ Else
+ ' No match, service is not in exclusion list.
+ ' Process and add to property bag
+ If Err.Number = 0 Then
+ With automaticService
+ Set scomPropertyBag = scomApi.CreatePropertyBag() ' Instance of a new property bag
+
+ ' Start adding values to the propertybag
+ Call scomPropertyBag.AddValue("Name",Cstr(.Name))
+ Call scomPropertyBag.AddValue("DisplayName",Cstr(.DisplayName))
+ If .Description <> vbNull Then
+ Call scomPropertyBag.AddValue("Description",Cstr(.Description))
+ Else
+ Call scomPropertyBag.AddValue("Description","")
+ End If
+ Call scomPropertyBag.AddValue("SystemName",Cstr(.SystemName))
+ Call scomPropertyBag.AddValue("PathName",Cstr(.PathName))
+ Call scomPropertyBag.AddValue("ProcessID",Cstr(.ProcessID))
+ If .StartName <> vbNull Then
+ Call scomPropertyBag.AddValue("ServiceUser",Cstr(.StartName))
Else
- Call scomPropertyBag.AddValue("Description","")
+ Call scomPropertyBag.AddValue("ServiceUser","")
End If
- Call scomPropertyBag.AddValue("SystemName",Cstr(.SystemName))
- Call scomPropertyBag.AddValue("PathName",Cstr(.PathName))
- Call scomPropertyBag.AddValue("ProcessID",Cstr(.ProcessID))
- Call scomPropertyBag.AddValue("ServiceUser",Cstr(.StartName))
- Call scomPropertyBag.AddValue("State",Cstr(.State))
- Call scomPropertyBag.AddValue("Status",Cstr(.Status))
- Call scomPropertyBag.AddValue("StartMode",Cstr(.StartMode))
- Call scomPropertyBag.AddValue("ServiceType",Cstr(.ServiceType))
- Call scomPropertyBag.AddValue("TagID",Cstr(.TagID))
-
- Call scomApi.AddItem(scomPropertyBag) ' Add the property bag to the collection
- End With
- Else
- Select Case returnValue
- Case 242100
- LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Could not properly connect to the service repository on " & computerName & ", check RunAs user rights."
- Case 242101
- LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Could not match registry value """ & serviceName & """to an existing service."
- Case 424
- LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Connection to WMI-service on " & computerName & " failed. Check network connections and RunAs user rights."
- Case Else
- LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "An unhandled script event occured, please contact your SCOM admins." & vbCrLf & "Err.number = " & Err.Number
- End Select
- End If 'End error check
- End If 'End exclusion check
-
+ Call scomPropertyBag.AddValue("State",Cstr(.State))
+ Call scomPropertyBag.AddValue("Status",Cstr(.Status))
+ Call scomPropertyBag.AddValue("StartMode",Cstr(.StartMode))
+ Call scomPropertyBag.AddValue("ServiceType",Cstr(.ServiceType))
+ Call scomPropertyBag.AddValue("TagID",Cstr(.TagID))
+
+ Call scomApi.AddItem(scomPropertyBag) ' Add the property bag to the collection
+ End With
+ Else
+ Select Case returnValue
+ Case 242100
+ LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Could not properly connect to the service repository on " & computerName & ", check RunAs user rights."
+ Case 242101
+ LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Could not match registry value """ & serviceName & """to an existing service."
+ Case 424
+ LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "Connection to WMI-service on " & computerName & " failed. Check network connections and RunAs user rights."
+ Case Else
+ LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "An unhandled script event occured, please contact your SCOM admins." & vbCrLf & "Err.number = " & Err.Number
+ End Select
+ End If 'End error check
+ End If 'End exclusion check
+
Set serviceObject = Nothing
Next
Call scomApi.ReturnItems() ' Return the property bag collection to SCOM
@@ -131,7 +135,7 @@ Sub CheckParameters(numRequiredParams)
'''
Dim scriptArguments
Set scriptArguments = WScript.Arguments
-
+
If IsNumeric(numRequiredParams) Then
If scriptArguments.Count >= numRequiredParams Then
Set scriptParameters = scriptArguments
@@ -153,7 +157,7 @@ Sub LogEvent(logEventID, logSeverity, logMessage)
'''
Dim scomApi, scriptName
scriptName = WScript.ScriptName
-
+
If logEventID <> SCOM_DEBUG Then
Set scomApi = CreateObject("MOM.ScriptAPI")
Call scomApi.LogScriptEvent(scriptName,logEventID,logSeverity,logMessage)
diff --git a/Atea.Windows.Service.Monitoring/Scripts/AteaWinSvcServiceDiscoveryDS.vbs b/Atea.Windows.Service.Monitoring/Scripts/AteaWinSvcServiceDiscoveryDS.vbs
index 58927c7..60499ab 100644
--- a/Atea.Windows.Service.Monitoring/Scripts/AteaWinSvcServiceDiscoveryDS.vbs
+++ b/Atea.Windows.Service.Monitoring/Scripts/AteaWinSvcServiceDiscoveryDS.vbs
@@ -35,7 +35,7 @@ If NOT IsNull(registryValues) Then
' We got a "hit" on a service name configured in the registry
' Create the SCOM property bag instances and return them to SCOM
Set scomApi = CreateObject("MOM.ScriptAPI")
-
+
For Each serviceName in registryValues
' Add one property bag per service
LogEvent SCOM_DEBUG,SCOM_INFO,"Found value: HKLM\" & keyPath & "\" & serviceName
@@ -59,7 +59,7 @@ If NOT IsNull(registryValues) Then
Call scomPropertyBag.AddValue("StartMode",.StartMode)
Call scomPropertyBag.AddValue("ServiceType",.ServiceType)
Call scomPropertyBag.AddValue("TagID",.TagID)
- Call scomPropertyBag.AddValue("keyPath",keyPath)
+ Call scomPropertyBag.AddValue("keyPath",keyPath)
Call scomApi.AddItem(scomPropertyBag) ' Add the property bag to the collection
End With
@@ -75,7 +75,7 @@ If NOT IsNull(registryValues) Then
LogEvent SCOM_SCRIPT_WARNING, SCOM_WARNING, "An unhandled script event occured, please contact your SCOM admins." & vbCrLf & "Err.number = " & returnValue
End Select
End If
-
+
Set serviceObject = Nothing
Next
Call scomApi.ReturnItems() ' Return the property bag collection to SCOM
@@ -86,26 +86,26 @@ If NOT IsNull(registryValues) Then
"Error code: " & Err.Num & vbCrLf & _
"Error Description: " & Err.Description
- ' Issue #4
- ' Discovery never removing services efter the only remaining string value is deleted.
- ' Needs to return an empty property bag.
- Set scomApi = CreateObject("MOM.ScriptingAPI")
- Set scomPropertyBag = scomApi.CreatePropertyBag()
- Call scomApi.Return(scomPropertyBag)
- Set scomApi = Nothing
+ ' Issue #4
+ ' Discovery never removing services efter the only remaining string value is deleted.
+ ' Needs to return an empty property bag.
+ Set scomApi = CreateObject("MOM.ScriptingAPI")
+ Set scomPropertyBag = scomApi.CreatePropertyBag()
+ Call scomApi.Return(scomPropertyBag)
+ Set scomApi = Nothing
End If
Else
' Could not read from registry, perhaps key is missing?
LogEvent SCOM_DEBUG,SCOM_INFO,"Failed to read from: HKLM\" & keyPath & "\"
- ' Issue #4
- ' Discovery never removing services efter the only remaining string value is deleted.
- ' Needs to return an empty property bag.
- Set scomApi = CreateObject("MOM.ScriptAPI")
- Set scomApi = CreateObject("MOM.ScriptingAPI")
- Set scomPropertyBag = scomApi.CreatePropertyBag()
- Call scomApi.Return(scomPropertyBag)
- Set scomApi = Nothing
+ ' Issue #4
+ ' Discovery never removing services efter the only remaining string value is deleted.
+ ' Needs to return an empty property bag.
+ Set scomApi = CreateObject("MOM.ScriptAPI")
+ Set scomApi = CreateObject("MOM.ScriptingAPI")
+ Set scomPropertyBag = scomApi.CreatePropertyBag()
+ Call scomApi.Return(scomPropertyBag)
+ Set scomApi = Nothing
End If
@@ -129,7 +129,7 @@ Sub CheckParameters(numRequiredParams)
'''
Dim scriptArguments
Set scriptArguments = WScript.Arguments
-
+
If IsNumeric(numRequiredParams) Then
If scriptArguments.Count >= numRequiredParams Then
Set scriptParameters = scriptArguments
@@ -151,7 +151,7 @@ Sub LogEvent(logEventID, logSeverity, logMessage)
'''
Dim scomApi, scriptName
scriptName = WScript.ScriptName
-
+
If logEventID <> SCOM_DEBUG Then
Set scomApi = CreateObject("MOM.ScriptAPI")
Call scomApi.LogScriptEvent(scriptName,logEventID,logSeverity,logMessage)
@@ -176,11 +176,11 @@ Class Service
Public Status
Public StartMode
Public ServiceType
- Public ProcessID
+ Public ProcessID
Public TagID
-
-
+
+
Private Sub Class_Initialize()
Name = ""
DisplayName = ""
@@ -192,7 +192,7 @@ Class Service
Public Function GetServiceInfo(mServiceName, mComputerName)
Dim wmi, wmiServices, wmiService, serviceClass, returnCode
-
+
returnCode = 0 ' 0 = no error
On Error Resume Next
Set wmi = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & mComputerName & "\root\cimv2")
@@ -202,19 +202,19 @@ Class Service
For Each wmiService In wmiServices
If LCase(wmiService.Name) = LCase(mServiceName) Then
Name = ClearIllegalReturnValues(wmiService.Name)
- DisplayName = ClearIllegalReturnValues(wmiService.Caption)
- Description = ClearIllegalReturnValues(wmiService.Description)
- ServiceUser = ClearIllegalReturnValues(wmiService.StartName)
- SystemName = ClearIllegalReturnValues(wmiService.SystemName)
- PathName = ClearIllegalReturnValues(wmiService.PathName)
- State = ClearIllegalReturnValues(wmiService.State)
- Status = ClearIllegalReturnValues(wmiService.Status)
- StartMode = ClearIllegalReturnValues(wmiService.StartMode)
- ServiceType = ClearIllegalReturnValues(wmiService.ServiceType)
- ProcessID = ClearIllegalReturnValues(wmiService.ProcessID)
- TagID = ClearIllegalReturnValues(wmiService.TagID)
- Else
- returnCode = 242101
+ DisplayName = ClearIllegalReturnValues(wmiService.Caption)
+ Description = ClearIllegalReturnValues(wmiService.Description)
+ ServiceUser = ClearIllegalReturnValues(wmiService.StartName)
+ SystemName = ClearIllegalReturnValues(wmiService.SystemName)
+ PathName = ClearIllegalReturnValues(wmiService.PathName)
+ State = ClearIllegalReturnValues(wmiService.State)
+ Status = ClearIllegalReturnValues(wmiService.Status)
+ StartMode = ClearIllegalReturnValues(wmiService.StartMode)
+ ServiceType = ClearIllegalReturnValues(wmiService.ServiceType)
+ ProcessID = ClearIllegalReturnValues(wmiService.ProcessID)
+ TagID = ClearIllegalReturnValues(wmiService.TagID)
+ Else
+ returnCode = 242101
End If
Next
Else
@@ -230,12 +230,12 @@ Class Service
Set wmiServices = Nothing
Set wmi = Nothing
End Function
-
+
Private Function ClearIllegalReturnValues(StringToClear)
- ' Check for NULL
- If IsNull(StringToClear) Then
- StringToClear = ""
- End If
- ClearIllegalReturnValues = StringToClear
+ ' Check for NULL
+ If IsNull(StringToClear) Then
+ StringToClear = ""
+ End If
+ ClearIllegalReturnValues = StringToClear
End Function
End Class
\ No newline at end of file
diff --git a/Atea.Windows.Service.Monitoring/Scripts/Get-RunningServices.ps1 b/Atea.Windows.Service.Monitoring/Scripts/Get-RunningServices.ps1
index 8cb1f0b..7f49c7b 100644
--- a/Atea.Windows.Service.Monitoring/Scripts/Get-RunningServices.ps1
+++ b/Atea.Windows.Service.Monitoring/Scripts/Get-RunningServices.ps1
@@ -1 +1 @@
-gwmi -query "select * from Win32_Service where State='Running'" | ft Name,DisplayName -AutoSize
+Get-WMIObject -query "select * from Win32_Service where State='Running'" | Format-Table Name,DisplayName -AutoSize
diff --git a/Atea.Windows.Service.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/AutoServiceDiscoveryVBSProbe.mpx b/Atea.Windows.Service.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/AutoServiceDiscoveryVBSProbe.mpx
index e03be12..f190398 100644
--- a/Atea.Windows.Service.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/AutoServiceDiscoveryVBSProbe.mpx
+++ b/Atea.Windows.Service.Monitoring/TypeLibrary/ModuleTypes/ProbeActions/AutoServiceDiscoveryVBSProbe.mpx
@@ -13,7 +13,7 @@
AteaAutoSvcPBScript.vbs
- $Config/ComputerName$ $Config/Debug$ $Config/ServiceExceptions$
+ $Config/ComputerName$ $Config/Debug$ "$Config/ServiceExceptions$"
$IncludeFileContent/Scripts/AteaAutoSvcPBScript.vbs$
$Config/TimeoutSeconds$
diff --git a/Atea.Windows.sln b/Atea.Windows.sln
index 70827ec..0109581 100644
--- a/Atea.Windows.sln
+++ b/Atea.Windows.sln
@@ -28,25 +28,24 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {361E64DE-7730-493D-8464-C22911EB5791}.Debug|x86.ActiveCfg = Debug|x86
- {361E64DE-7730-493D-8464-C22911EB5791}.Debug|x86.Build.0 = Debug|x86
+ {361E64DE-7730-493D-8464-C22911EB5791}.Debug|x86.ActiveCfg = Release|x86
+ {361E64DE-7730-493D-8464-C22911EB5791}.Debug|x86.Build.0 = Release|x86
{361E64DE-7730-493D-8464-C22911EB5791}.Release|x86.ActiveCfg = Release|x86
{361E64DE-7730-493D-8464-C22911EB5791}.Release|x86.Build.0 = Release|x86
- {E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Debug|x86.ActiveCfg = Debug|x86
- {E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Debug|x86.Build.0 = Debug|x86
+ {E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Debug|x86.ActiveCfg = Release|x86
+ {E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Debug|x86.Build.0 = Release|x86
{E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Release|x86.ActiveCfg = Release|x86
{E346D1C7-2CA1-4E15-A871-663F747FBFDE}.Release|x86.Build.0 = Release|x86
- {53470240-D3B9-4EF1-B4E1-6A075FB07593}.Debug|x86.ActiveCfg = Debug|x86
- {53470240-D3B9-4EF1-B4E1-6A075FB07593}.Debug|x86.Build.0 = Debug|x86
+ {53470240-D3B9-4EF1-B4E1-6A075FB07593}.Debug|x86.ActiveCfg = Release|x86
+ {53470240-D3B9-4EF1-B4E1-6A075FB07593}.Debug|x86.Build.0 = Release|x86
{53470240-D3B9-4EF1-B4E1-6A075FB07593}.Release|x86.ActiveCfg = Release|x86
{53470240-D3B9-4EF1-B4E1-6A075FB07593}.Release|x86.Build.0 = Release|x86
- {C55B880E-F609-462C-AED3-67F44531D4D7}.Debug|x86.ActiveCfg = Debug|x86
- {C55B880E-F609-462C-AED3-67F44531D4D7}.Debug|x86.Build.0 = Debug|x86
+ {C55B880E-F609-462C-AED3-67F44531D4D7}.Debug|x86.ActiveCfg = Release|x86
+ {C55B880E-F609-462C-AED3-67F44531D4D7}.Debug|x86.Build.0 = Release|x86
{C55B880E-F609-462C-AED3-67F44531D4D7}.Release|x86.ActiveCfg = Release|x86
{C55B880E-F609-462C-AED3-67F44531D4D7}.Release|x86.Build.0 = Release|x86
- {1783668C-8085-419E-B862-D3CFEE8401AC}.Debug|x86.ActiveCfg = Debug
+ {1783668C-8085-419E-B862-D3CFEE8401AC}.Debug|x86.ActiveCfg = Release
{1783668C-8085-419E-B862-D3CFEE8401AC}.Release|x86.ActiveCfg = Release
- {1783668C-8085-419E-B862-D3CFEE8401AC}.Release|x86.Build.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6b3b5a..4e82df7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,14 +11,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Automatic builds and MSI-packaging to /Release folder
- Powershell based installation/update scripts
- This changelog!
+- File Age Monitor
### Changed
- Updated documentation design
+- Install Script no longer uses the MSI-file, works directly with mp-files
### Fixed
- [Svc Recovery alert has wrong eventlog name #6](https://github.com/stegenfeldt/Atea.Windows/issues/6)
- Reconfigured Auto Deploy after extension update
- Adv Service Recovery logging to task output
+- Exclusions on AutoService discovery
+- Standard Service Restart recovery task now supports services with spaces
### Removed
- Old Downloads folder
diff --git a/README.md b/README.md
index 18df454..2aeab60 100644
--- a/README.md
+++ b/README.md
@@ -2,22 +2,33 @@
The Atea.Windows MP collection is a number of, somewhat related, management packs developed by Atea Sverige AB for our customers.
+[![Build Status](https://stegenfeldt.visualstudio.com/SCOM%20MP%20-%20Atea.Windows/_apis/build/status/stegenfeldt.Atea.Windows)](https://stegenfeldt.visualstudio.com/SCOM%20MP%20-%20Atea.Windows/_build/latest?definitionId=1)
+
+## Tools needed
+
+This project is built using Visual Studio 2017 (Community).
+In addition to that, you'd need the following extensions:
+
+- VSAE - Visual Studio Authoring Extensions
+- Auto Deploy -
+- Microsoft Visual Studio 2017 Installer Projects
+
## Customers/Sponsors
The following customers have graciously allowed us to co-develop this MP and share our work with our other customers and the rest of the world.
-* Clas Ohlson
-* Spendrups
-* ABB
-* Borlänge Kommun
-* Piteå Kommun
-* Atea Integration Services
-* Landstinget Gävleborg
-* SSAB
-* Xylem Water Solutions
+- Clas Ohlson
+- Spendrups
+- ABB
+- Borlänge Kommun
+- Piteå Kommun
+- Atea Integration Services
+- Region Gävleborg
+- SSAB
+- Xylem Water Solutions
## Disclaimer
-While most of this is developed from scratch, some inspiration has been taken from other community members.
+While most of this is developed from scratch, some inspiration has been taken from other community members.
In such case, we have tried to include links in the comments.
If you think we have missed something, please let me know and we will add the proper credits.
diff --git a/Released/Atea.Windows.File.Monitoring.mp b/Released/Atea.Windows.File.Monitoring.mp
index 8039c9b..fe85ee4 100644
Binary files a/Released/Atea.Windows.File.Monitoring.mp and b/Released/Atea.Windows.File.Monitoring.mp differ
diff --git a/Released/Atea.Windows.Installer.msi b/Released/Atea.Windows.Installer.msi
index f0deaa8..68074a2 100644
Binary files a/Released/Atea.Windows.Installer.msi and b/Released/Atea.Windows.Installer.msi differ
diff --git a/Released/Atea.Windows.Library.mp b/Released/Atea.Windows.Library.mp
index b5ca56d..eb95a17 100644
Binary files a/Released/Atea.Windows.Library.mp and b/Released/Atea.Windows.Library.mp differ
diff --git a/Released/Atea.Windows.Server.Monitoring.mp b/Released/Atea.Windows.Server.Monitoring.mp
index 81312f0..6a6a808 100644
Binary files a/Released/Atea.Windows.Server.Monitoring.mp and b/Released/Atea.Windows.Server.Monitoring.mp differ
diff --git a/Released/Atea.Windows.Service.Monitoring.mp b/Released/Atea.Windows.Service.Monitoring.mp
index 852b0eb..a03b9ba 100644
Binary files a/Released/Atea.Windows.Service.Monitoring.mp and b/Released/Atea.Windows.Service.Monitoring.mp differ
diff --git a/Released/Install-AteaWindowsMP.ps1 b/Released/Install-AteaWindowsMP.ps1
index cec6e56..466fa36 100644
--- a/Released/Install-AteaWindowsMP.ps1
+++ b/Released/Install-AteaWindowsMP.ps1
@@ -28,27 +28,51 @@ Defaults to the local computer. Set this to connect to a different SCOM Manageme
#>
[CmdletBinding()]
param(
- [ValidateSet("Stable","Latest")][string] $Version,
+ [Parameter(Mandatory = $true)]
+ [ValidateSet("Stable","Latest")] [string] $Version,
[switch] $ImportMP,
[string] $OMMSComputerName = "."
)
-[string] $developURL = "https://github.com/stegenfeldt/Atea.Windows/raw/develop/Released/Atea.Windows.Installer.msi"
-[string] $masterURL = "https://github.com/stegenfeldt/Atea.Windows/raw/master/Released/Atea.Windows.Installer.msi"
+$Error.Clear()
+[string[]] $mpFiles = @(
+ "Atea.Windows.Library.mp",
+ "Atea.Windows.Server.Monitoring.mp",
+ "Atea.Windows.Service.Monitoring.mp",
+ "Atea.Windows.File.Monitoring.mp"
+)
+
+[string] $developURL = "https://github.com/stegenfeldt/Atea.Windows/raw/develop/Released/"
+[string] $masterURL = "https://github.com/stegenfeldt/Atea.Windows/raw/master/Released/"
[string] $installDir = "$(${env:ProgramFiles(x86)})\System Center Management Packs\Atea.Windows\"
-[string] $msiFilePath = "$($env:TEMP)\Atea.Windows.Installer.msi"
-
-[string] $packageName = "Atea Windows - MP Package"
-
-if ($Version = "Stable") {
- Invoke-WebRequest -Uri $masterURL -OutFile $msiFilePath
- if (Get-Package -Name $packageName -ErrorAction SilentlyContinue) {Uninstall-Package -Name $packageName -Force}
- Install-Package -Name $msiFilePath -Force
-} elseif ($Version = "Latest") {
- Invoke-WebRequest -Uri $developURL -OutFile $msiFilePath
- if (Get-Package -Name $packageName -ErrorAction SilentlyContinue) {Uninstall-Package -Name $packageName -Force}
- Install-Package -Name $msiFilePath -Force
+$startLocation = Get-Location
+
+if ((Test-Path $installDir) -eq $false) {
+ if (!(New-Item -Path $installDir -ItemType Directory -Force -ErrorAction SilentlyContinue)) {
+ Write-Host "Unable to create directory." -ForegroundColor Red
+ Write-Host "Using current directory instead."
+ $installDir = "$($Script:PWD.Path)\"
+ }
+}
+
+foreach ($mpFile in $mpFiles) {
+ switch ($Version) {
+ "Stable" {
+ $mpFilePath = $installDir + $mpFile
+ $mpFileURL = $masterURL + $mpFile
+ }
+ "Latest" {
+ $mpFilePath = $installDir + $mpFile
+ $mpFileURL = $developURL + $mpFile
+ }
+ default {
+ $mpFilePath = $installDir + $mpFile
+ $mpFileURL = $masterURL + $mpFile
+ }
+ }
+ Write-Verbose "Saving $mpFileURL to $mpFilePath"
+ Invoke-WebRequest -Uri $mpFileURL -OutFile $mpFilePath
}
if ($ImportMP -and (($Version = "Stable") -or ($Version = "Latest"))) {
@@ -56,5 +80,165 @@ if ($ImportMP -and (($Version = "Stable") -or ($Version = "Latest"))) {
New-SCOMManagementGroupConnection -ComputerName $OMMSComputerName
$mps = Get-SCOMManagementPack -ManagementPackFile (Get-ChildItem -Path $installDir -Filter "*.mp").FullName
+ Write-Verbose "Importing managementpacks to $((Get-SCOMManagementGroup).Name)"
Import-SCOMManagementPack -ManagementPack $mps -Verbose
}
+
+# SIG # Begin signature block
+# MIIdGQYJKoZIhvcNAQcCoIIdCjCCHQYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
+# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
+# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU2Ocvbmr8ERmgRnPwUnP5QWcG
+# 4pGgghg5MIIE3jCCA8agAwIBAgIQazJqDwMo03odUwv9I71I4jANBgkqhkiG9w0B
+# AQsFADB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp
+# ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+# MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTE1MTAyOTEx
+# MzAyOVoXDTI3MDYwOTExMzAyOVowgYAxCzAJBgNVBAYTAlBMMSIwIAYDVQQKDBlV
+# bml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLDB5DZXJ0dW0gQ2VydGlm
+# aWNhdGlvbiBBdXRob3JpdHkxJDAiBgNVBAMMG0NlcnR1bSBDb2RlIFNpZ25pbmcg
+# Q0EgU0hBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALfbqNjI47za
+# 2oO6ub/W1VdTQbdAuhcMRJXU6WY7f7S+kKOUCaWtISAXgEa0QyY+jksaZOwOQDJD
+# /IKf/0ot6pTdWhE2i2Hv7BbUSQPY513DZVvyTgsrw8FT+kAtwqszJAWBcH7Ih0yf
+# 0YDCGHsOFL1OA0PLKEiwLeY23xs9i8OMnTee4QbXJVDfeT3at1/rRr52KDa4AgBG
+# A9A0G3i0KMdRx8iVP26NiRjcSfHCDxr0gYHHbdQEd8Uhoy5T+XfP3Kmbw8Hl1Wcv
+# MbzAwmicSpblH/HzSDUO9uSxxe+HgDrigAw0nfoUZHHkHKGqss8Ap+M3cvlArZ4o
+# lQINzpDjW8UCAwEAAaOCAVMwggFPMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+# FMB7tMi3blanCUia+HJP19ckLDY+MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C8
+# 4oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzAvBgNV
+# HR8EKDAmMCSgIqAghh5odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYS5jcmwwawYI
+# KwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0
+# dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv
+# Y3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw
+# Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAKrlP3ZUAkxw
+# DimpOZYGDzG3C/Gmi1L7EI9PQluMvTEjAWad6CmhTcNQ+vf4RQ4dgtf8/qYyBHP9
+# cezMiA+jkgjFgVgC/QtpO824P0k90I0cExRoLpsNmq2wGeKe0nw5d4hvI/17hPxE
+# bbW6a3CSVWyUsdg3/alZHbRjstwTzXiOJTXBmo83hC7URczj9cyNc6jjOm3nlZRw
+# V5FQtm3vc3JPLwKHYOLqIqHtPv3Ri2aNLnJtT8ZdNe6TqJjSZ2rp2hnNAoP5dPxf
+# ehgEKB7dIjM7dmxHBV3VUv4OunbzgxDHbjBfp2DH+nQnMZsog+0hihvxI1KE7ZW8
+# rTqlo0IBnbwwggYUMIIE/KADAgECAhBurXO+EeW89wo8twyKIm/WMA0GCSqGSIb3
+# DQEBCwUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UECgwZVW5pemV0byBUZWNobm9s
+# b2dpZXMgUy5BLjEnMCUGA1UECwweQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9y
+# aXR5MSQwIgYDVQQDDBtDZXJ0dW0gQ29kZSBTaWduaW5nIENBIFNIQTIwHhcNMTYx
+# MDI3MDkxOTM2WhcNMTcxMDI3MDkxOTM2WjCBjTELMAkGA1UEBhMCU0UxHjAcBgNV
+# BAoMFU9wZW4gU291cmNlIERldmVsb3BlcjExMC8GA1UEAwwoT3BlbiBTb3VyY2Ug
+# RGV2ZWxvcGVyLCBTYW11ZWwgVGVnZW5mZWxkdDErMCkGCSqGSIb3DQEJARYcc2Ft
+# dWVsLnRlZ2VuZmVsZHRAaGFydGF0aS5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+# ADCCAQoCggEBANwPjeTu0SLUiZc1k8pkKP8IZk7Id0obvTTQeXmp9xhvxsypLJUk
+# eC33s5avefEjOJVf8oYW99XGUyYdgcJO22XWkxIq5uWbN+idhxI13kcwGTX9xp0a
+# pH6FCvDkraCwtqmUSEl1dISOY4JBv1pMRf+919K/7qEQW7YH9Cl/3nH/qYTpUMkG
+# TUwY58YB8qUwxCVa8A0w4FY0rHwx7Ds4VPWwq8zbPEKX7OO7HBQ2tQb4tc4Yuq5v
+# HY5o60zPE8ZuYJllOfn9p6TFUBSQ3T2+zX14fF/Wz3cIfwDEzVZ1jX10CuF81yxP
+# ihgdxOxI5ujh/jfJsS8svmsTrmiuODLdO00CAwEAAaOCAnkwggJ1MAwGA1UdEwEB
+# /wQCMAAwMgYDVR0fBCswKTAnoCWgI4YhaHR0cDovL2NybC5jZXJ0dW0ucGwvY3Nj
+# YXNoYTIuY3JsMHEGCCsGAQUFBwEBBGUwYzArBggrBgEFBQcwAYYfaHR0cDovL2Nz
+# Y2FzaGEyLm9jc3AtY2VydHVtLmNvbTA0BggrBgEFBQcwAoYoaHR0cDovL3JlcG9z
+# aXRvcnkuY2VydHVtLnBsL2NzY2FzaGEyLmNlcjAfBgNVHSMEGDAWgBTAe7TIt25W
+# pwlImvhyT9fXJCw2PjAdBgNVHQ4EFgQUlV5XwtpXLs0CQdomBbg3c6JM0xcwHQYD
+# VR0SBBYwFIESY3NjYXNoYTJAY2VydHVtLnBsMA4GA1UdDwEB/wQEAwIHgDCCATgG
+# A1UdIASCAS8wggErMIIBJwYFZ4EMAQQwggEcMCUGCCsGAQUFBwIBFhlodHRwczov
+# L3d3dy5jZXJ0dW0ucGwvQ1BTMIHyBggrBgEFBQcCAjCB5TAgFhlVbml6ZXRvIFRl
+# Y2hub2xvZ2llcyBTLkEuMAMCAQEagcBVc2FnZSBvZiB0aGlzIGNlcnRpZmljYXRl
+# IGlzIHN0cmljdGx5IHN1YmplY3RlZCB0byB0aGUgQ0VSVFVNIENlcnRpZmljYXRp
+# b24gUHJhY3RpY2UgU3RhdGVtZW50IChDUFMpIGluY29ycG9yYXRlZCBieSByZWZl
+# cmVuY2UgaGVyZWluIGFuZCBpbiB0aGUgcmVwb3NpdG9yeSBhdCBodHRwczovL3d3
+# dy5jZXJ0dW0ucGwvcmVwb3NpdG9yeS4wEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJ
+# KoZIhvcNAQELBQADggEBAIkXhtrsJL9eEUKfia5fS1s5S5RI3JlLV0sFFl72zvGV
+# F2bxxQkAf8xh30ft5N5N7ZwM3jDc52Q+vjttiXsBwTkqId2MgF8p7YvEGTMoDQiU
+# rYOB82QY3Fbdz3dKViRi7/xm6aUHNsWmw/fUWZC8HAncRTQr5t35q3XmmFR+Xc+W
+# Qgpfpjqbge9K2MEhLU6/wIUnqLsXXz3fHVEMwKqO6rQKo8nHUNGK9wxzZhBZIQJh
+# Dw+c0KJl7k4Avqqriv/NtkwSYepgV1tCU2wFcwTiwuuUGe3rfgrW1vT5Fb7D3ddw
+# gVj1HZNtmWcP9eRF2Uv5P6iblqN+H557h3yHYgR5QSkwggZqMIIFUqADAgECAhAD
+# AZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMRUw
+# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
+# ITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTAeFw0xNDEwMjIwMDAw
+# MDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdp
+# Q2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1wIFJlc3BvbmRlcjCCASIw
+# DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8s+CCNeDg9sYq5kl1O8xu
+# 4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7dy4XpX6X51Id0iEQ7Gcnl
+# 9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGfrvP9Enh1DqZbFP1FI46G
+# RFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5uHzu5uc0LzF3gTAfuzYB
+# je8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYuRhDIjegEYNu8c3T6Ttj+
+# qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJCkawCwO+k8IkRj3cCAwEA
+# AaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB
+# /wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIwggGhBglghkgBhv1sBwEw
+# ggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIIB
+# ZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkA
+# cwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUA
+# cwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkA
+# QwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkA
+# aQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMA
+# aAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIA
+# ZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkA
+# IAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwDFTAfBgNVHSMEGDAWgBQV
+# ABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpNJLZJMp1KKnkag0v0HonB
+# yn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
+# Z2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0dHA6Ly9jcmw0LmRpZ2lj
+# ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3JsMHcGCCsGAQUFBwEBBGsw
+# aTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUF
+# BzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk
+# SURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+GzNNsiaBXJuGziMgD4CH
+# 5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94GAYw3+puxnSR+/iCkV61b
+# t5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFBpr1i2fAnPTgdKG86Ugnw
+# 7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dxnSHdFMoVXZJB2vkPgdGZ
+# dA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bIo4sKHOWV2q7ELlmgYd3a
+# 822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQKOhvjjz3Kr2qNe9zYRDCC
+# Bs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJKoZIhvcNAQEFBQAwZTEL
+# MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+# LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290
+# IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAwMFowYjELMAkGA1UEBhMC
+# VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0
+# LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBDQS0xMIIBIjANBgkq
+# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKVpYBzQHDSnlZUXKnE0kEG
+# j8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqvy15r7a2wcTHrzzpADEZN
+# k+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/2DDD/6b3+6LNb3Mj/qxW
+# BZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE7h6z8rwMK5nQxl0SQoHh
+# g26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKvmPv2zkBdXPao8S+v7Iki
+# 8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIUYJX9BwSiCQIDAQABo4ID
+# ejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIGCCsGAQUFBwMBBggrBgEF
+# BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCDCCAdIGA1UdIASCAckw
+# ggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cu
+# ZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcC
+# AjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIA
+# dABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMA
+# ZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAA
+# QwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAA
+# YQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0A
+# aQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMA
+# bwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUA
+# cgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB/wQIMAYBAf8CAQAweQYI
+# KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j
+# b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp
+# Q2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6
+# Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww
+# OqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
+# RFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e36K+Vw0rZwLNMB8GA1Ud
+# IwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUAA4IBAQBG
+# UD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90OPKyXGGinJXDUOSCuSPR
+# ujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann4+erYs37iy2QwsDStZS9
+# Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qqq8+cdkvtX8JLFuRLcEwA
+# iR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD7eeSDY2xaYxP+1ngIw/S
+# qq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38KiGtSTGDR5V3cdyxG0tL
+# HBCcdxTBnU8vWpUIKRAmMYIESjCCBEYCAQEwgZUwgYAxCzAJBgNVBAYTAlBMMSIw
+# IAYDVQQKDBlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLDB5DZXJ0
+# dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAiBgNVBAMMG0NlcnR1bSBDb2Rl
+# IFNpZ25pbmcgQ0EgU0hBMgIQbq1zvhHlvPcKPLcMiiJv1jAJBgUrDgMCGgUAoHgw
+# GAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC
+# NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQx
+# FgQUa/R0nwlVeyne5Vbw6COxLmsNVwwwDQYJKoZIhvcNAQEBBQAEggEAmgkqvheB
+# qmFWz3l8ZRQ/rJ1pYAIcpJyiJuyhr5WRumWLQuY+EFqumL00eRiAUDX8VJV3eCFM
+# 3rojWPXbPFdOmA3HLaaL0spBS0HMSHivgIw+nGP9emNDjoENcTiZQVeld2cwEslk
+# 1VTKwDrxOqikbfxCpKjkDNCj800Uu6KGkmR4pY/dpZ8/aUHQJBgA1bggkmPO4FCy
+# eWi9cBUjE2Fv6NV4c02Ob06yOqnDqeRWpWOsJiL3fzlO0ELswYm7zRPrjF7Ell/K
+# p+2a6YVceAbuN+hewBeCh6AQ8GOv+AReRdzn2FhnJPXtxfxn3CKqhPI2OEakp1TF
+# KfNWh6HYlPA+A6GCAg8wggILBgkqhkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJ
+# BgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
+# aWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQ
+# AwGaAjr/WLFr1tXq5hfwZjAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqG
+# SIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTcwNDA2MTMwMDAwWjAjBgkqhkiG9w0B
+# CQQxFgQUiytB1wxiYtV0tXKzdsWvzY8/RLMwDQYJKoZIhvcNAQEBBQAEggEAA81G
+# vmmZtrwxKybdjFwanXGUasZQKZVFuB5I7fPRx+U5v4qCxaWYupfisKOhKmftIMFW
+# +6zW1aq6TVVdYOjxtftkigQ962Q/vgH+aw7s0+PFm/s7+AdSMSUEq2ZT0x/VaWYB
+# X53VXBpgwdJI7gTadryH2zSf8MMkfZKLMKDU+j6YdfhUH950IC0cELDc/PolQoQu
+# PDqiSv+jmzTMGVsdjVRo2iiT6cW/dDJ+bvGhzPPxk3wHhYahgHJFrYVgHvZxn2PY
+# dDvL8hsdJfKoc6FZ2Irjvn0Ud1Sb4bsyKghx+WFPOvIV/Y3RRJ9Ljog79X5HX19m
+# 2UCBHdjyddFDobvMYg==
+# SIG # End signature block
diff --git a/_Scripts/PostBuild.ps1 b/_Scripts/PostBuild.ps1
new file mode 100644
index 0000000..5bb9678
--- /dev/null
+++ b/_Scripts/PostBuild.ps1
@@ -0,0 +1,7 @@
+param (
+ [string] $FilePath
+)
+
+#signtool sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /sha1 5E1D01C6F02199D1A39D806EB17A961F5C476EE2 "$(OutDir)$(TargetFileName)"
+Set-AuthenticodeSignature -Certificate (dir Cert:\CurrentUser\My\5E1D01C6F02199D1A39D806EB17A961F5C476EE2) -TimestampServer "http://timestamp.digicert.com" -FilePath "$($FilePath)"
+Set-AuthenticodeSignature -Certificate (dir Cert:\CurrentUser\My\5E1D01C6F02199D1A39D806EB17A961F5C476EE2) -TimestampServer "http://timestamp.digicert.com" -FilePath "$($FilePath.Substring(0,$FilePath.LastIndexOfAny("\"))+"\Setup.exe")"
diff --git a/_Scripts/azure-pipelines-extinstall.ps1 b/_Scripts/azure-pipelines-extinstall.ps1
new file mode 100644
index 0000000..d8eeb57
--- /dev/null
+++ b/_Scripts/azure-pipelines-extinstall.ps1
@@ -0,0 +1,17 @@
+$vsaeUrl = "https://download.microsoft.com/download/4/4/6/446B60D0-4409-4F94-9433-D83B3746A792/VisualStudioAuthoringConsole_x64.msi"
+$vsaeFileName = "VisualStudioAuthoringConsole_x64.msi"
+$vsaePackageName = "System Center Visual Studio Authoring Extensions"
+
+Invoke-WebRequest -Uri $vsaeUrl -Method Get -OutFile $vsaeFileName -Verbose
+
+$vsaeInstalled = Get-Package -IncludeWindowsInstaller -Name $vsaePackageName -Verbose
+if (!$vsaeInstalled) {
+ Write-Host "VSAE Not Installed!"
+ Write-Host "Attempting install..."
+ Install-Package -InputObject (Find-Package -Name ".\$vsaeFileName") -Verbose
+} else {
+ Write-Host "VSAE Already installed!"
+}
+
+Write-Host "Copying SignKey..."
+Copy-Item -Path $env:DOWNLOADSECUREFILE_SECUREFILEPATH -Destination ".\" -Verbose
\ No newline at end of file
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 0000000..0c2318e
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,39 @@
+# .NET Desktop
+# Build and run tests for .NET Desktop or Windows classic desktop solutions.
+# Add steps that publish symbols, save build artifacts, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
+
+pool:
+ vmImage: 'VS2017-Win2016'
+
+variables:
+ solution: '**/*.sln'
+ buildPlatform: #'Any CPU'
+ buildConfiguration: 'Release'
+
+steps:
+- task: NuGetToolInstaller@0
+
+- task: NuGetCommand@2
+ inputs:
+ restoreSolution: '$(solution)'
+
+- task: DownloadSecureFile@1
+ inputs:
+ secureFile: 'AteaST.snk'
+
+- task: Powershell@2
+ inputs:
+ targetType: filePath
+ filePath: '$(Build.SourcesDirectory)\_Scripts\azure-pipelines-extinstall.ps1'
+
+- task: VSBuild@1
+ inputs:
+ solution: '$(solution)'
+ platform: '$(buildPlatform)'
+ configuration: '$(buildConfiguration)'
+
+- task: VSTest@2
+ inputs:
+ platform: '$(buildPlatform)'
+ configuration: '$(buildConfiguration)'
diff --git a/docs/Files/FileAgeMonitoring_Example1.reg b/docs/Files/FileAgeMonitoring_Example1.reg
new file mode 100644
index 0000000..c147159
Binary files /dev/null and b/docs/Files/FileAgeMonitoring_Example1.reg differ