Created
October 15, 2014 16:31
-
-
Save adbertram/3d820b6062c2b30cdaca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 4 | |
<# | |
.NOTES | |
Created on: 10/8/2014 | |
Created by: Adam Bertram | |
Filename: Start-ModPollMonitor.ps1 | |
Requirements: Share permissions for Everyone on destination share | |
The source computer account Modify NTFS rights on destination folder | |
.DESCRIPTION | |
.EXAMPLE | |
PS> .\Start-ModPollMonitor.ps1 | |
.PARAMETER SourceFolderPath | |
This is the folder path on the local computer that will be monitored for | |
new files. | |
.PARAMETER DestinationHost | |
The destination host that the file will be copied to | |
.PARAMETER DestinationFileShare | |
The share name on the destination host where the file will be copied to | |
.PARAMETER FileExtension | |
This is the file extension that, when placed into SourceFolderPath path | |
will kick off the Modbus process. This defaults to PDF. | |
.PARAMETER ModPollFilePath | |
The file path where the modpoll.exe file is located | |
.PARAMETER FailureSourceFolderPath | |
The path to the local folder that all failed modpoll files will be placed. | |
This is only used if the file copy is unsuccessful. | |
.PARAMETER MonitorIntervalSecs | |
The number of seconds between script runs. | |
.PARAMETER LogFilePath | |
The file path to the log file that's generated with the progress of the | |
script. This defaults to C:\Windows\Temp\Start-ModPollMonitor.log | |
#> | |
[CmdletBinding(SupportsShouldProcess)] | |
param ( | |
[Parameter()] | |
[ValidateScript({ | |
if (!(Test-Path -Path $_ -PathType Container)) { | |
throw "The source folder path '$($_)' cannot be found" | |
} else { | |
$true | |
} | |
})] | |
[string]$SourceFolderPath = 'C:\TestSourceFolder\folder', | |
[Parameter()] | |
[ValidateScript({ | |
if (!(Test-Connection -ComputerName $_ -Quiet -Count 1)) { | |
throw "The destination host '$($_)' does not appear to be online" | |
} else { | |
$true | |
} | |
})] | |
[string]$DestinationHost = 'labdc.lab.local', | |
[Parameter()] | |
[string]$DestinationFileShare = 'plcscript', | |
[Parameter()] | |
[ValidatePattern('^\w{3}$')] | |
[string]$FileExtension = 'pdf', | |
[ValidateScript({ | |
if (!(Test-Path -Path $_ -PathType Leaf)) { | |
throw "Modpoll.exe cannot be found at '$($_)'" | |
} else { | |
$true | |
} | |
})] | |
[string]$ModPollFilePath = 'C:\Users\administrator.LAB\Dropbox\Side Business\GitHubRepos\MiscScripts\PLCScript\Source\modpoll.exe', | |
[ValidateScript({ | |
if (!(Test-Path -Path $_ -PathType Container)) { | |
throw "The failure source folder path '$($_)' cannot be found" | |
} else { | |
$true | |
} | |
})] | |
[string]$FailureSourceFolderPath = 'C:\FailureSourceFolder', | |
[Parameter()] | |
[int]$MonitorIntervalSecs = 10, | |
[Parameter()] | |
[string]$LogFilePath = "$([environment]::GetEnvironmentVariable('TEMP','Machine'))\Start-ModPollMonitor.log" | |
) | |
begin { | |
function Write-Log { | |
<# | |
.SYNOPSIS | |
This function creates or appends a line to a log file | |
.DESCRIPTION | |
This function writes a log line to a log file | |
.PARAMETER Message | |
The message parameter is the log message you'd like to record to the log file | |
.PARAMETER LogLevel | |
The logging level is the severity rating for the message you're recording. | |
You have 3 severity levels available; 1, 2 and 3 from informational messages | |
for FYI to critical messages. This defaults to 1. | |
.EXAMPLE | |
PS C:\> Write-Log -Message 'Value1' -LogLevel 'Value2' | |
This example shows how to call the Write-Log function with named parameters. | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter( | |
Mandatory = $true)] | |
[string]$Message, | |
[Parameter()] | |
[ValidateSet(1, 2, 3)] | |
[int]$LogLevel = 1 | |
) | |
try { | |
$TimeGenerated = "$(Get-Date -Format HH:mm:ss).$((Get-Date).Millisecond)+000" | |
## Build the line which will be recorded to the log file | |
$Line = '{2} {1}: {0}' | |
$LineFormat = $Message, $TimeGenerated, (Get-Date -Format MM-dd-yyyy) | |
$Line = $Line -f $LineFormat | |
Add-Content -Value $Line -Path $LogFilePath | |
} catch { | |
Write-Error $_.Exception.Message | |
} | |
} | |
function Convert-ToUncPath($LocalFolderPath, $Computername) { | |
$RemoteFolderPathDrive = ($LocalFolderPath | Split-Path -Qualifier).TrimEnd(':') | |
"\\$Computername\$RemoteFolderPathDrive`$$($LocalFolderPath | Split-Path -NoQualifier)" | |
} | |
function Send-PollToModbusSlave ($PollNumber,$RegisterNumber) { | |
Write-Log -Message "Polling the Modbus slave with poll number $PollNumber" | |
$Result = Start-Process -FilePath $ModPollFilePath -ArgumentList "-r$RegisterNumber localhost $PollNumber" -Wait -NoNewWindow -PassThru | |
Start-Sleep -Seconds 2 | |
if ($Result.ExitCode -ne 0) { | |
Write-Log -Message 'Poll to modbus slave failed' -LogLevel '3' | |
$false | |
} else { | |
Write-Log -Message 'Poll to modbus slave succeeded' | |
$true | |
} | |
} | |
function Validate-ModbusSlaveRunning { | |
Write-Log -Message 'Validating the Modbus slave is running' | |
$Result = Start-Process -FilePath $ModPollFilePath -ArgumentList "-r1 localhost $((get-date).Second)" -Wait -NoNewWindow -PassThru | |
Start-Sleep -Seconds 2 | |
if ($Result.ExitCode -ne 0) { | |
Write-Log -Message 'Modbus slave is not running' -LogLevel '2' | |
$false | |
} else { | |
Write-Log -Message 'Modbus slave is running' | |
$true | |
} | |
} | |
function Start-ModbusSlave { | |
if (Test-Path 'C:\Program Files (x86)\Everest\Tools\PeakHmiMBTCPSlave.exe') { | |
Start-Process -FilePath 'C:\Program Files (x86)\Everest\Tools\PeakHmiMBTCPSlave.exe' -NoNewWindow | |
} elseif (Test-Path 'C:\Program Files\Everest\Tools\PeakHmiMBTCPSlave.exe') { | |
Start-Process -FilePath 'C:\Program Files\Everest\Tools\PeakHmiMBTCPSlave.exe' -NoNewWindow | |
} | |
Write-Log -Message 'Modbus slave started' | |
if (!(Validate-ModbusSlaveRunning)) { | |
throw 'Attempted to start Modbus slave but failed.' | |
} else { | |
Write-Log -Message 'Successfully started modbus slave' | |
$true | |
} | |
} | |
function Start-FileCopyProcess ($FilePath, $DestUncFolderPath) { | |
Write-Log -Message "Starting file copy of '$FilePath' to '$DestUncFolderPath'" | |
$SourceHash = (Get-FileHash $FilePath).Hash | |
Write-Log -Message "Source hash for '$FilePath' is '$SourceHash'" | |
Copy-Item -Path $FilePath -Destination $DestUncFolderPath | |
$DestUncFilePath = "$DestUncFolderPath\$($FilePath | Split-Path -Leaf)" | |
$DestHash = (Get-FileHash $DestUncFilePath).Hash | |
Write-Log -Message "Dest hash for '$DestUncFilePath' is '$DestHash'" | |
if ($SourceHash -ne $DestHash) { | |
Write-Log -Message "Source and destination file hash differ post file-copy. Copy failed." -LogLevel '2' | |
Write-Log -Message "Moving $FilePath to $FailureSourceFolderPath" -LogLevel '2' | |
Move-Item -Path $FilePath -Destination $FailureSourceFolderPath -Force | |
} else { | |
Write-Log -Message "Successfully copied file '$FilePath' to '$DestUncFolderPath' after 1 try" | |
Send-PollToModbusSlave -PollNumber 2 -RegisterNumber 1 | |
Write-Log -Message "Removing the file '$FilePath'" | |
Remove-Item $FilePath -Force | |
} | |
} | |
function New-FileMonitor { | |
$WmiEventFilterQuery = " | |
SELECT * FROM __InstanceCreationEvent WITHIN $MonitorIntervalSecs | |
WHERE targetInstance ISA 'CIM_DataFile' | |
AND targetInstance.Drive = `"$WmiEventSourceDrive`" | |
AND targetInstance.Path = `"$($WmiEventSourceFolderPath.Replace('\','\\'))`" | |
AND targetInstance.Extension = `"$FileExtension`"" | |
$WmiFilterParams = @{ | |
'Class' = '__EventFilter' | |
'Namespace' = 'root\subscription' | |
'Arguments' = @{ Name = 'NewFile'; EventNameSpace = 'root\cimv2'; QueryLanguage = 'WQL'; Query = $WmiEventFilterQuery } | |
} | |
$WmiEventFilterPath = Set-WmiInstance @WmiFilterParams | |
$WmiConsumerParams = @{ | |
'Class' = 'ActiveScriptEventConsumer' | |
'Namespace' = 'root\subscription' | |
'Arguments' = @{ Name = 'CopyFile'; ScriptFileName = $WmiEventLaunchScriptFilePath; ScriptingEngine = 'VBscript' } | |
} | |
$WmiConsumer = Set-WmiInstance @WmiConsumerParams | |
$WmiFilterConsumerParams = @{ | |
'Class' = '__FilterToConsumerBinding' | |
'Namespace' = 'root\subscription' | |
'Arguments' = @{ Filter = $WmiEventFilterPath; Consumer = $WmiConsumer } | |
} | |
Set-WmiInstance @WmiFilterConsumerParams | Out-Null | |
} | |
function Validate-IsFileMonitorCreated { | |
Get-WmiObject -Namespace 'root\subscription' -Class __FilterToConsumerBinding -Filter { Consumer = 'ActiveScriptEventConsumer.Name="CopyFile"' } | |
} | |
try { | |
$WorkingDir = $MyInvocation.MyCommand.Path | Split-Path -Parent | |
$WmiEventLaunchScriptFilePath = Get-ChildItem $WorkingDir -Filter *.vbs | select -ExpandProperty fullname | |
$WmiEventSourceFolderPath = "$($SourceFolderPath | Split-Path -NoQualifier)\" | |
$WmiEventSourceDrive = $SourceFolderPath | Split-Path -Qualifier | |
if ($WmiEventLaunchScriptFilePath -is [array]) { | |
throw "Multiple VBS files located in '$WorkingDir'. Only a single launch VBS should exist" | |
} | |
} catch { | |
Write-Log -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" -LogLevel '3' | |
exit | |
} | |
} | |
process { | |
try { | |
if (!(Validate-ModbusSlaveRunning)) { | |
Write-Log -Message 'Modbus slave not running. Attempting to start' | |
Start-ModbusSlave | |
} | |
if (!(Validate-IsFileMonitorCreated)) { | |
Write-Log -Message 'The file copy monitor has not been created yet. Creating now' | |
New-FileMonitor | |
#} elseif () { | |
# Write-Warning 'The file copy process is still running. Skipping this time' | |
# exit | |
} | |
Send-PollToModbusSlave -PollNumber (Get-Date).Seconds -RegisterNumber 2 | |
$SourceFiles = Get-ChildItem $SourceFolderPath -Filter "*.$FileExtension" -File | |
if ($SourceFiles) { | |
Write-Log -Message "Found $($SourceFiles.Count) files to attempt to copy." | |
$DestUncFolderPath = "\\$DestinationHost\$DestinationFileShare" | |
Write-Log -Message "Destination folder path is '$DestUncFolderPath'" | |
if (!(Test-Path $DestUncFolderPath)) { | |
throw "Destination folder path '$DestUncFolderPath' does not exist on remote computer" | |
} | |
if (!(Send-PollToModbusSlave -PollNumber 1 -RegisterNumber 1)) { | |
throw "Failed to poll modbus slave with poll number 1" | |
} | |
$SourceFiles | foreach { | |
Start-FileCopyProcess -DestUncFolderPath $DestUncFolderPath -FilePath $_.FullName | |
} | |
} else { | |
Write-Log -Message "No $FileExtension files to process yet" | |
} | |
$FailedFiles = Get-ChildItem $FailureSourceFolderPath -File | |
if ($FailedFiles) { | |
Write-Log -Message "Found $($FailedFiles.Count) failed file to attempt to copy." | |
foreach ($File in $FailedFiles) { | |
Start-FileCopyProcess -DestUncFolderPath $DestUncFolderPath -FilePath $File.FullName | |
} | |
$FailedFiles = Get-ChildItem $FailureSourceFolderPath -File | |
if (!$FailedFiles) { | |
Write-Log -Message "Successfully copied all failed files from '$FailureSourceFolderPath'" | |
if (!(Send-PollToModbusSlave -PollNumber 2 -RegisterNumber 1)) { | |
throw "Failed to poll modbus slave with poll number 2" | |
} | |
} else { | |
throw "Failed to copy all failed files from '$FailureSourceFolderPath'" | |
} | |
} else { | |
Write-Log -Message 'No previously failed file copies to process' | |
} | |
} catch { | |
Write-Log -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" -LogLevel '3' | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment