I'm having an issue that I have not run into before. I have one MP where I have a module setup to run a PowerShell script every 5mins. The script is supposed to grab all PDFs in a folder and depending on size/age/matching XML, be copied/moved to several directories. I've now run it dozens of times manually without a single issue. However, when I wrap it up in a SCOM monitor, it sometimes (but not always)copies the actual PDF directory into the target directory for the move. I setup some logging inside the PowerShell script and it appears to not match the script criteria (or the parameters are being mangled). I'm wondering if anyone has run into a similar issue? Here are the two log entries.
Manual Execution: ======================================================================== 11/06/2015 09:26:41 | Processing Started: Good_File.pdf 11/06/2015 09:26:41 | Good_File.pdf is 209KB 11/06/2015 09:26:41 | XML pair found: Good_File.xml 11/06/2015 09:26:41 | Good_File.pdf copy to C:\Folder\Prod\PDF\Archive success 11/06/2015 09:26:41 | Good_File.pdf move to C:\Program Files (x86)\Acme\Outbound success 11/06/2015 09:26:41 | Processing Complete: Good_File.pdf 11/06/2015 09:26:41 | Good_File.xml copy to C:\Folder\Prod\PDF\Archive success 11/06/2015 09:26:41 | Good_File.xml move to C:\Program Files (x86)\Acme\Outbound success 11/06/2015 09:26:41 | Processing Complete: Good_File.xml ======================================================================== SCOM Execution: ======================================================================== 11/05/2015 21:26:59 | Processing Started: 11/05/2015 21:26:59 | is 0KB 11/05/2015 21:26:59 | XML pair found: .xml 11/05/2015 21:26:59 | Processing Complete: 11/05/2015 21:26:59 | .xml copy to C:\Folder\Prod\PDF\Archive failed 11/05/2015 21:26:59 | .xml move to C:\Program Files (x86)\Acme\Outbound failed 11/05/2015 21:26:59 | Processing Complete: .xml ======================================================================== When executing via SCOM there are random instances where the PDF folder in C:\Folder\Prod is being moved to C:\Program Files (x86)\Acme\Outbound: [cid:[email protected]] I cannot reproduce this when executing my script manually; I only see it when run via SCOM. The difference with manual is I am defining the variables within my PS session ($directory, $errordir, etc.) prior to running the script. With SCOM, the parameters are supposed to be passed in so I don't have to hard code them in the PowerShell script (per Brian Wren's training videos). I am attaching the test MP I am using for this. If there are any insight, I'm really interested to know if there is an issue/limitation related to PowerShell/SCOM I need to account for or if it's a problem with my MP authoring. Thank you very much. Geoff Confidentiality Notice: This is a transmission from Community Hospital of the Monterey Peninsula. This message and any attached documents may be confidential and contain information protected by state and federal medical privacy statutes. They are intended only for the use of the addressee. If you are not the intended recipient, any disclosure, copying, or distribution of this information is strictly prohibited. If you received this transmission in error, please accept our apologies and notify the sender. Thank you.
<?xml version="1.0" encoding="utf-8"?> <ManagementPack SchemaVersion="2.0" ContentReadable="true" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Manifest> <Identity> <ID>Acme.Test</ID> <Version>1.0.0.15</Version> </Identity> <Name>Acme.Test</Name> <References> <Reference Alias="Windows"> <ID>Microsoft.Windows.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="Health"> <ID>System.Health.Library</ID> <Version>7.0.8433.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="System"> <ID>System.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> </References> </Manifest> <TypeDefinitions> <EntityTypes> <ClassTypes> <ClassType ID="Acme.Test.Servers" Base="Windows!Microsoft.Windows.ComputerRole" Accessibility="Public" Abstract="false" Hosted="true" Singleton="false" /> </ClassTypes> </EntityTypes> <ModuleTypes> <DataSourceModuleType ID="Acme.Test.DataSource.ProcessFolderPDFs.PropertyBag" Accessibility="Internal"> <Configuration> <xsd:element name="IntervalSeconds" type="xsd:integer" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="SyncTime" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="Directory" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ErrorDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ArchiveDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="OutboxDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="LogFilePath" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> </Configuration> <OverrideableParameters> <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" /> <OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string" /> </OverrideableParameters> <ModuleImplementation> <Composite> <MemberModules> <DataSource ID="Schedule" TypeID="System!System.SimpleScheduler"> <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds> <SyncTime>$Config/SyncTime$</SyncTime> </DataSource> <ProbeAction ID="Script" TypeID="Acme.Test.Probe.ProcessFolderPDFs"> <Directory>$Config/Directory$</Directory> <ErrorDir>$Config/ErrorDir$</ErrorDir> <ArchiveDir>$Config/ArchiveDir$</ArchiveDir> <OutboxDir>$Config/OutboxDir$</OutboxDir> <LogFilePath>$Config/LogFilePath$</LogFilePath> </ProbeAction> </MemberModules> <Composition> <Node ID="Script"> <Node ID="Schedule" /> </Node> </Composition> </Composite> </ModuleImplementation> <OutputType>System!System.PropertyBagData</OutputType> </DataSourceModuleType> <ProbeActionModuleType ID="Acme.Test.Probe.ProcessFolderPDFs" Accessibility="Internal"> <Configuration> <xsd:element name="Directory" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ErrorDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ArchiveDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="OutboxDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="LogFilePath" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> </Configuration> <ModuleImplementation> <Composite> <MemberModules> <ProbeAction ID="Script" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe"> <ScriptName>FolderPDFs.ps1</ScriptName> <ScriptBody><![CDATA[param($directory, $ErrorDir, $ArchiveDir, $OutboxDir, $LogFilePath) $api = new-object -comObject 'MOM.ScriptAPI' $api.LogScriptEvent("FolderPDFs.ps1",2500,0,"Starting PDF Process in $Directory") # Function for outputting information to log file. function Write-Log { [cmdletbinding()] Param( [Parameter(Mandatory=$true, Position=0)] [string]$Message ) if($LogFilePath) { Add-Content -Path "$LogFilePath" -Value "$(Get-Date) | $Message$newLine" } } function Write-Result { param( [Parameter(Mandatory=$true,Position=0)] $FileName, [Parameter(Mandatory=$true,Position=1)] [ValidateSet('copy','move')] $Action, [Parameter(Mandatory=$true,Position=2)] $Directory, [Parameter(Mandatory=$true,Position=3)] $Error ) If($Error) { Write-Log "$Filename $Action to $Directory failed" }Else{ Write-Log "$Filename $Action to $Directory success" } } function File-Action { param( [Parameter(Mandatory=$false,Position=0)] $SourceDir, [Parameter(Mandatory=$false,Position=1)] $FileName, [Parameter(Mandatory=$false,Position=2)] $TargetDir, [Switch]$Copy, $CopyTo ) If($copy) { Copy-Item "$($SourceDir)\$($FileName)" -Destination $CopyTo -ErrorVariable Fail -ErrorAction SilentlyContinue Write-Result $FileName copy $CopyTo -Error $Fail } Move-Item "$($SourceDir)\$($FileName)" -Destination $TargetDir -ErrorVariable Fail -ErrorAction SilentlyContinue Write-Result $FileName move $TargetDir -Error $Fail Write-Log "Processing Complete: $FileName" } function Start-Log { Add-Content -Path $LogFilePath -Value "========================================================================" Write-Log "Processing Started: $File" $Size = "{0:N0}" -f ($File.Length / 1Kb) Write-Log "$File is $($size + 'KB')" } $GoodFiles = $null $BadWithXMLs = $null $BadFiles = $null # Gather file types based on size, age, existence of XML pair # $ProcessFileCount = (Get-ChildItem $Directory | Where-Object {$_.Name -like "*.pdf"} | Measure-Object).Count $GoodFiles = Get-ChildItem $Directory | Where {($_.Name -like '*.pdf') -and ($_.CreationTime -lt (Get-Date).AddMinutes(-5) -and ($_.Length -gt 15kb) -and (Test-Path "$($Directory)\$($_.BaseName + '.xml')"))} $BadWithXMLs = Get-ChildItem $Directory | Where {($_.Name -like '*.pdf') -and ($_.CreationTime -lt (Get-Date).AddMinutes(-5) -and ($_.Length -lt 15kb) -and (Test-Path "$($Directory)\$($_.BaseName + '.xml')"))} $BadFiles = Get-ChildItem $Directory | Where {($_.Name -like '*.pdf') -and ($_.CreationTime -lt (Get-Date).AddMinutes(-5) -and ($_.Length -lt 15kb) -and -not (Test-Path "$($Directory)\$($_.BaseName + '.xml')"))} Foreach($File in $GoodFiles) { Start-Log Write-Log "XML pair found: $($File.BaseName + '.xml')" File-Action $Directory $File $OutboxDir -Copy -CopyTo $ArchiveDir File-Action $Directory $($File.BaseName + '.xml') $OutboxDir -Copy -CopyTo $ArchiveDir } Foreach($File in $BadFiles) { Start-Log Write-Log "$File is smaller than 15KB" Write-Log "No matching XML" File-Action $Directory $File $ErrorDir } Foreach($File in $BadWithXMLs) { Start-Log Write-Log "$File is smaller than 15KB" Write-Log "XML pair found: $($File.BaseName + '.xml')" File-Action $Directory $File $ErrorDir File-Action $Directory $($File.Basename + '.xml') $ErrorDir } If(($GoodFiles -eq $null) -and ($BadFiles -eq $null) -and ($BadWithXMLs -eq $null)) { Add-Content -Path $LogFilePath -Value "========================================================================" Write-Log "Zero PDF files found matching criteria" } # Get Error File information and output to Property Bag for SCOM Processing # $folderitems = Get-ChildItem $ErrorDir | foreach {$_.Name} $filelist=[string]::join([environment]::newline, $folderitems) $FileCount = (Get-ChildItem $ErrorDir | Measure-Object).Count $bag = $api.CreatePropertyBag() $bag.AddValue('Directory',$directory) $bag.AddValue('FileCount',$filecount) $bag.AddValue('FileList',$filelist) $bag.AddValue('ErrorDir',$ErrorDir) $bag # Write results to Operations Manager Log in Event Viewer # If($FileCount -gt 0){ $api.LogScriptEvent("FolderPDFs.ps1",2500,1,"PDF Processing completed. Files Processed: $ProcessFileCount. Error Files: $FileCount") }Else{ $api.LogScriptEvent("FolderPDFs.ps1",2500,0,"PDF Processing completed. Files Processed: $ProcessFileCount. Error Files: $FileCount") }]]></ScriptBody> <Parameters> <Parameter> <Name>Directory</Name> <Value>$Config/Directory$</Value> </Parameter> <Parameter> <Name>ErrorDir</Name> <Value>$Config/ErrorDir$</Value> </Parameter> <Parameter> <Name>ArchiveDir</Name> <Value>$Config/ArchiveDir$</Value> </Parameter> <Parameter> <Name>OutboxDir</Name> <Value>$Config/OutboxDir$</Value> </Parameter> <Parameter> <Name>LogFilePath</Name> <Value>Config/LogFilePath$</Value> </Parameter> </Parameters> <TimeoutSeconds>120</TimeoutSeconds> </ProbeAction> </MemberModules> <Composition> <Node ID="Script" /> </Composition> </Composite> </ModuleImplementation> <OutputType>System!System.PropertyBagData</OutputType> <TriggerOnly>true</TriggerOnly> </ProbeActionModuleType> </ModuleTypes> <MonitorTypes> <UnitMonitorType ID="Acme.Test.MonitorType.ProcessFolderPDFs" Accessibility="Internal"> <MonitorTypeStates> <MonitorTypeState ID="UnderThreshold" NoDetection="false" /> <MonitorTypeState ID="OverErrorThreshold" NoDetection="false" /> </MonitorTypeStates> <Configuration> <xsd:element name="IntervalSeconds" type="xsd:integer" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="SyncTime" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="Directory" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ErrorDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="ArchiveDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="OutboxDir" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="LogFilePath" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> <xsd:element name="Threshold" type="xsd:integer" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> </Configuration> <OverrideableParameters> <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" /> <OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string" /> <OverrideableParameter ID="Threshold" Selector="$Config/Threshold$" ParameterType="string" /> </OverrideableParameters> <MonitorImplementation> <MemberModules> <DataSource ID="DS" TypeID="Acme.Test.DataSource.ProcessFolderPDFs.PropertyBag"> <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds> <SyncTime>$Config/SyncTime$</SyncTime> <Directory>$Config/Directory$</Directory> <ErrorDir>$Config/ErrorDir$</ErrorDir> <ArchiveDir>$Config/ArchiveDir$</ArchiveDir> <OutboxDir>$Config/OutboxDir$</OutboxDir> <LogFilePath>$Config/LogFilePath$</LogFilePath> </DataSource> <ProbeAction ID="Probe" TypeID="Acme.Test.Probe.ProcessFolderPDFs"> <Directory>$Config/Directory$</Directory> <ErrorDir>$Config/ErrorDir$</ErrorDir> <ArchiveDir>$Config/ArchiveDir$</ArchiveDir> <OutboxDir>$Config/OutboxDir$</OutboxDir> <LogFilePath>$Config/LogFilePath$</LogFilePath> </ProbeAction> <ConditionDetection ID="FilterUnderThreshold" TypeID="System!System.ExpressionFilter"> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="Integer">Property[@Name='FileCount']</XPathQuery> </ValueExpression> <Operator>Less</Operator> <ValueExpression> <Value Type="Integer">$Config/Threshold$</Value> </ValueExpression> </SimpleExpression> </Expression> </ConditionDetection> <ConditionDetection ID="FilterOverThreshold" TypeID="System!System.ExpressionFilter"> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="Integer">Property[@Name='FileCount']</XPathQuery> </ValueExpression> <Operator>GreaterEqual</Operator> <ValueExpression> <Value Type="Integer">$Config/Threshold$</Value> </ValueExpression> </SimpleExpression> </Expression> </ConditionDetection> </MemberModules> <RegularDetections> <RegularDetection MonitorTypeStateID="UnderThreshold"> <Node ID="FilterUnderThreshold"> <Node ID="DS" /> </Node> </RegularDetection> <RegularDetection MonitorTypeStateID="OverErrorThreshold"> <Node ID="FilterOverThreshold"> <Node ID="DS" /> </Node> </RegularDetection> </RegularDetections> <OnDemandDetections> <OnDemandDetection MonitorTypeStateID="UnderThreshold"> <Node ID="FilterUnderThreshold"> <Node ID="Probe" /> </Node> </OnDemandDetection> <OnDemandDetection MonitorTypeStateID="OverErrorThreshold"> <Node ID="FilterOverThreshold"> <Node ID="Probe" /> </Node> </OnDemandDetection> </OnDemandDetections> </MonitorImplementation> </UnitMonitorType> </MonitorTypes> </TypeDefinitions> <Monitoring> <Discoveries> <Discovery ID="Acme.Test.Discover.TestComputer" Target="Windows!Microsoft.Windows.Computer" Enabled="true" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryClass TypeID="Acme.Test.Servers" /> </DiscoveryTypes> <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider"> <ComputerName>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</ComputerName> <RegistryAttributeDefinitions> <RegistryAttributeDefinition> <AttributeName>KeyExists</AttributeName> <Path>SOFTWARE\Acme-SCOM\TestKey</Path> <PathType>0</PathType> <AttributeType>0</AttributeType> </RegistryAttributeDefinition> </RegistryAttributeDefinitions> <Frequency>1200</Frequency> <ClassId>$MPElement[Name="Acme.Test.Servers"]$</ClassId> <InstanceSettings> <Settings> <Setting> <Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name> <Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value> </Setting> <Setting> <Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name> <Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value> </Setting> </Settings> </InstanceSettings> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery>Values/KeyExists</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value>true</Value> </ValueExpression> </SimpleExpression> </Expression> </DataSource> </Discovery> </Discoveries> <Monitors> <UnitMonitor ID="Acme.Test.Monitor.FolderPDF" Accessibility="Internal" Enabled="true" Target="Acme.Test.Servers" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="Acme.Test.MonitorType.ProcessFolderPDFs" ConfirmDelivery="false"> <Category>AvailabilityHealth</Category> <AlertSettings AlertMessage="Acme.Test.Monitor.FolderPDF.AlertMessage"> <AlertOnState>Error</AlertOnState> <AutoResolve>true</AutoResolve> <AlertPriority>Normal</AlertPriority> <AlertSeverity>MatchMonitorHealth</AlertSeverity> <AlertParameters> <AlertParameter1>$Data/Context/Property[@Name='FileCount']$</AlertParameter1> <AlertParameter2>$Data/Context/Property[@Name='ErrorDir']$</AlertParameter2> <AlertParameter3>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</AlertParameter3> <AlertParameter4>$Data/Context/Property[@Name='FileList']$</AlertParameter4> </AlertParameters> </AlertSettings> <OperationalStates> <OperationalState ID="UnderThreshold" MonitorTypeStateID="UnderThreshold" HealthState="Success" /> <OperationalState ID="OverErrorThreshold" MonitorTypeStateID="OverErrorThreshold" HealthState="Error" /> </OperationalStates> <Configuration> <IntervalSeconds>300</IntervalSeconds> <SyncTime /> <Directory>C:\Folder\Prod\PDF</Directory> <ErrorDir>C:\Folder\Prod\PDF\Error</ErrorDir> <ArchiveDir>C:\Folder\Prod\PDF\Archive</ArchiveDir> <OutboxDir>C:\Program Files (x86)\Acme\Outbound</OutboxDir> <LogFilePath>C:\Folder\Prod\PDF\Log\FileSizeCheck.log</LogFilePath> <Threshold>1</Threshold> </Configuration> </UnitMonitor> </Monitors> </Monitoring> <Presentation> <StringResources> <StringResource ID="Acme.Test.Monitor.FolderPDF.AlertMessage" /> </StringResources> </Presentation> <LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <DisplayString ElementID="Acme.Test.Monitor.FolderPDF"> <Name>Test: Process Folder PDFs</Name> <Description></Description> </DisplayString> <DisplayString ElementID="Acme.Test.Monitor.FolderPDF.AlertMessage"> <Name>Acme Test: Folder PDF Process</Name> <Description>{0} file(s) detected in "{1}" directory on {2}. Directory Listing: {3}</Description> </DisplayString> <DisplayString ElementID="Acme.Test.Monitor.FolderPDF" SubElementID="UnderThreshold"> <Name>UnderThreshold</Name> <Description>UnderThreshold</Description> </DisplayString> <DisplayString ElementID="Acme.Test.Monitor.FolderPDF" SubElementID="OverErrorThreshold"> <Name>OverErrorThreshold</Name> <Description>OverErrorThreshold</Description> </DisplayString> <DisplayString ElementID="Acme.Test"> <Name>Acme Test MP</Name> </DisplayString> <DisplayString ElementID="Acme.Test.Servers"> <Name>SCOM Test Servers</Name> <Description></Description> </DisplayString> <DisplayString ElementID="Acme.Test.Discover.TestComputer"> <Name>Discover: Test Computer</Name> <Description>Description for the new discovery.</Description> </DisplayString> </DisplayStrings> <KnowledgeArticles></KnowledgeArticles> </LanguagePack> </LanguagePacks> </ManagementPack>
