How to send email for multiple files uploaded in one email - powershell

I am using a powershell script that monitors a folder for new files added. This script works great the only problem is that it sends an email for every new file added. I can't seem how to get it to send a single email for all files added if a user was to drag and drop multiple files to folder. For instance if a user drops 3 files in the folder it should send one email with the links to all three files. This is my first time using powershell scripts.
PowerShell.exe -windowstyle hidden{
$MonitorFolder = "C:\Users\RickG\Desktop\Test Reports"
$MonitorStopFile = "monitor.die"
$smtpServer = "mail.rtg.org"
$smtpFrom = "SYSTEMFUNCTION#rtg.org"
$smtpTo = "rickg#rtg.org"
$smtpSubject = "New file arrived in $($MonitorFolder)."
$SourceID = "MonitorFiles"
$Query = #"
SELECT * FROM __InstanceCreationEvent WITHIN 10
WHERE targetInstance ISA 'Cim_DirectoryContainsFile'
AND targetInstance.GroupComponent = 'Win32_Directory.Name="$($MonitorFolder.Replace("\", "\\\\"))"'
"#
Try {
$smtp = New-Object -TypeName "Net.Mail.SmtpClient" -ArgumentList $smtpServer
Register-WmiEvent -Query $Query -SourceIdentifier $SourceID
Do {
"Waiting for a new file to arrive in '$($MonitorFolder)'; to stop, hit <Ctrl-C> or create a file '$MonitorStopFile'." | Write-Host
$FileEvent = Wait-Event -SourceIdentifier $SourceID
Remove-Event -EventIdentifier $FileEvent.EventIdentifier
$FileName = $FileEvent.SourceEventArgs.NewEvent.TargetInstance.PartComponent.Split("=", 2)[1].Trim('"').Replace("\\", "\")
If ((Split-Path -Path $FileName -Leaf) -eq $MonitorStopFile) {
$smtpBody = "[$(Get-Date -Format HH:mm:ss)]`tStop file arrived: '$($FileName)'; monitor is going down!"
Remove-Item -Path (Join-Path -Path $MonitorFolder -ChildPath $MonitorStopFile)
$FileEvent = $Null
} Else {
$smtpBody = "[$(Get-Date -Format HH:mm:ss)]`tNew file arrived: $($FileName)"
}
$smtpBody | Write-Host -Fore Yellow
$smtp.Send($smtpFrom, $smtpTo, $smtpSubject, $smtpBody)
} While ($FileEvent)
} Catch {
$_ | Out-String | Write-Error
} Finally {
Remove-Event -SourceIdentifier $SourceID -ErrorAction SilentlyContinue
Unregister-Event -SourceIdentifier $SourceID -ErrorAction SilentlyContinue
}
}
Also I am trying to make the file a link in the body of the email. I have tried this line with no luck.
$smtpBody = "[$(Get-Date -Format HH:mm:ss)]`tNew file arrived: <a href='$($FileName)'>$($FileName)</a>"

Related

Using Powershell to backup remote computers event logs

I'm very new to PowerShell and my end goal is to backup event logs on remote servers to a fileshare on the network. I was able to get my script working locally on a single server, backing up the servers event logs to a folder. Now, I'm trying to run this script from "server A" and backup event logs on "Server B" and "Server C". I was hoping I can accomplish this via simply creating a new ps session for each server and copy pasting my code. This of course wasn't the case. I'm guessing I might have to go through and add -Computer parameters to somethings?
I got the foundational code from this website
Was hoping a PS guru could point out my failures, here's my code:
$Servers = 'ServerB'
$ArchiveServer = 'ServerA' #For Testing
foreach ($Server in $Servers){
Enter-PSSession -ComputerName $Server -Credential mycred
$RemoteArchive = "\\" + $ArchiveServer +"\c$\z-TestScript-lastname"
$LocalArchive = "C:\z-TestScript"
$ArchiveComp = "\$Server"
$ArchiveFolder = "\Archive-" + (Get-Date -Format "yyyy-MM-dd") + "test14" ### Added test to get past testpath check
$RemoteLogFolder = "\\" + $Server + "\c$\Windows\System32\winevt\Logs"
$LogFolder = "C:\Windows\System32\winevt\Logs\*"
$RemoteCompressedPath = -join("$RemoteArchive","$ArchiveComp","$ArchiveFolder",".zip")
$CompressedPath = -join("$ArchiveLoc","$ArchiveComp","$ArchiveFolder",".zip")
$RemoteArchivePath = -join("$RemoteArchive","$ArchiveComp","$ArchiveFolder")
$ArchivePath = -join("$ArchiveLoc","$ArchiveComp","$ArchiveFolder")
$winlogs = 'application', 'security', 'system', 'setup', 'hardwareevents', 'internet explorer', 'key management service', 'oalerts', 'Parameters', 'oneapp_IGCC', 'windows powershell'
# Checking paths
If (!(Test-Path $RemoteArchive)) {
Write-Host
Write-Host "Archive folder $RemoteArchive does not exist, aborting ..." -ForegroundColor Red
Exit
}
If ((Test-Path $RemoteArchivePath)) {
Write-Host
Write-Host "Archive path $RemoteArchivePath exists, aborting ..." -ForegroundColor Red
Exit
}
If (!(Test-Path $RemoteArchivePath)) {
Write-Host
Write-Host "Creating Archive folder $RemoteArchivePath ..." -ForegroundColor Red
New-Item -Path $RemoteArchivePath -type directory -Force
}
# For all newer event logs, archive.
foreach ($winlog in $winlogs) {
# Configure environment
$sysName = $Server
$eventName = "$winlog Event Log Monitoring"
# Add event source to log if necessary
If (-NOT ([System.Diagnostics.EventLog]::SourceExists($eventName))) {
New-EventLog -ComputerName $Server -LogName $winlog -Source $eventName
}
# Check the log
if ( $winlog -ne 'Setup'){
$Log = Get-WmiObject Win32_NTEventLogFile | Where-Object {$_.logfilename -eq "$winlog"}
# Archive the log
$ArchiveFile = $ArchivePath + "\$winlog-" + (Get-Date -Format "yyyy-MM-dd#HHmm") + ".evt"
$EventMessage = "The $winlog event log will now be backed up."
$Results = ($Log.BackupEventlog($ArchiveFile)).ReturnValue
If ($Results -eq 0) {
# Successful backup of the event log
$Results = ($Log.ClearEventlog()).ReturnValue
$EventMessage += "The $winlog event log was successfully archived to $ArchiveFile and cleared."
Write-Host $EventMessage
Write-EventLog -LogName $winlog -Source $eventName -EventId 11 -EntryType Information -Message $eventMessage -Category 0
}
Else {
$EventMessage += "The #winlog event log could not be archived to $ArchiveFile and was not cleared. Review and resolve security event log issues on $sysName ASAP!"
Write-Host $EventMessage
Write-EventLog -LogName $winlog -Source $eventName -EventId 11 -EntryType Error -Message $eventMessage -Category 0
}
# Close the log
$Log.Dispose()
}
# For older archives like setup, archive.
Else {
$Log = Get-winevent -Listlog Setup | select Logname, Logfilepath | ForEach-Object -Process {
$name = $_.Logname
$safename = $name.Replace("/","-")
$logpath = $_.Logfilepath
$path = $ArchivePath + "\Setup" + (Get-Date -Format "yyyy-MM-dd#HHmm") + ".evt"
wevtutil.exe EPL $safename $path
Write-Host "Copying Setup log to: $path"
}
}
}
#Copy any windows archived logs over, then delete
Write-Host "Copying Archived Logs..."
Get-ChildItem -Path $LogFolder -Include Archive* -Recurse | Copy-Item -Destination $ArchivePath
Get-ChildItem -Path $LogFolder -Include Archive* -Recurse | Remove-Item
#Compress the folder
Write-Host "Compressing $ArchivePath and moving to $CompressedPath"
Compress-Archive -Path $ArchivePath -Destination $CompressedPath
Exit-PSSession
}
Main errors I'm getting as it goes through the foreach loop for the winlogs, it seems to run it twice, once for remote pc and once for local.

Filesystemwatcher file created event not decompressing files

I got a simple script that should watch for new files in specified folder and uncompress them on arriving. Simple, but my script only works under the debugger of Powershell ISE. When outside the debugger, on file creation it only prints "New file xxx found" and "Done", without decompressing it, nor deleting, but also no errors. I'm I missing something here?
# Folder you to monitor
$PathToMonitor = "C:\tmp1".
$OutputPath = "C:\tmp"
$Filter = "*.zip" # Filter for zip files.
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $false
$FileSystemWatcher.Filter = $Filter
# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# define the code that should execute when a file change is detected
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
Write-Host "New file " + $FullPath + " found"
$TarProgram = "tar.exe"
$TarArgs = 'xvf "' + $FullPath + '" -C ' + $OutputPath
Start-Process $TarProgram $TarArgs -Wait -WindowStyle hidden
Remove-Item -Path $FullPath -Force
Write-Host "Done"
}
catch [System.SystemException]
{
Write-Host $_.ScriptStackTrace
}
}
# add event handlers
$handlers = . {
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreateFtpGe
}
Write-Host "Watching for changes to $PathToMonitor"
try
{
do
{
Wait-Event -Timeout 10
} while ($true)
}
catch [System.SystemException]
{
Write-Host $_.ScriptStackTrace
}
finally
{
# this gets executed when user presses CTRL+C
# remove the event handlers
Write-Host "Cleaning up"
Unregister-Event -SourceIdentifier FSCreateFtpGe
# remove background jobs
$handlers | Remove-Job
# remove filesystemwatcher
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
"Event Handler disabled."
}
Why do you have a period here...
$PathToMonitor = "C:\tmp1".
...that is invalid syntax and the script should fail anyway. Yet, that could be just a type you did on posting here.
Why are you using tar vs the PowerShell built-in archive cmdlets?
if tar.exe is not in your PowerShell or system paths, you have to fully qualify that path to it for it to be used.
$TarProgram = 'C:\ProgramFiles\tar.exe'
So, your code should work in any PowerShell host (ISE [in/out of debug mode])/powershell.exe/VSCode, et al. AS I just tested it. Yet again, the cmdlets are there. Example of the below running in the new Windows Terminal.
#region Begin Script
# Folder you to monitor
$PathToMonitor = 'D:\tmp1'
$OutputPath = 'D:\tmp'
$Filter = '*.zip' # Filter for zip files.
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $false
$FileSystemWatcher.Filter = $Filter
# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# define the code that should execute when a file change is detected
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
"New file $FullPath found"
Expand-Archive -Path $FullPath -DestinationPath 'D:\tmp'
# Start-Process $TarProgram $TarArgs -Wait -WindowStyle hidden
Remove-Item -Path $FullPath -Force
'Done'
}
catch [System.SystemException]
{$PSItem.ScriptStackTrace}
}
# add event handlers
$handlers = . {
$RegisterObjectEventSplat = #{
InputObject = $FileSystemWatcher
EventName = 'Created'
Action = $Action
SourceIdentifier = 'FSCreateFtpGe'
}
Register-ObjectEvent #RegisterObjectEventSplat
}
"Watching for changes to $PathToMonitor"
try
{
do { Wait-Event -Timeout 10 }
while ($true)
}
catch [System.SystemException]
{$_.ScriptStackTrace}
finally
{
<#
this gets executed when user presses CTRL+C
remove the event handlers
#>
'Cleaning up'
Unregister-Event -SourceIdentifier FSCreateFtpGe
# remove background jobs
$handlers |
Remove-Job
# remove filesystemwatcher
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
'Event Handler disabled.'
}
#endregion End Script
# Results
Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property Caption, Version
Caption Version
$PSVersionTable
Name Value
---- -----
PSVersion 5.1.18362.752
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752}
BuildVersion 10.0.18362.752
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
Get-ChildItem -Path 'D:\tmp' -Verbose
(Get-ChildItem -Path 'D:\tmp').Count
0
Get-ChildItem -Path 'D:\tmp1' -Verbose
(Get-ChildItem -Path 'D:\tmp1').Count
0
.\FSWCopyUnzip.ps1
Watching for changes to D:\tmp1
New file D:\tmp1\book1.zip found
Done
Cleaning up
Get-ChildItem -Path 'D:\tmp' -Verbose
Directory: D:\tmp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 13-Mar-20 12:19 70 abc.txt
-a---- 13-Mar-20 22:27 71 book1.txt
-a---- 06-Apr-20 21:51 2979 Data.zip
-a---- 04-Mar-20 01:04 72 FileWithLines.txt
Get-ChildItem -Path 'D:\tmp1' -Verbose
(Get-ChildItem -Path 'D:\tmp1').Count
0
Just for the records, I found the issue. It's somehow related to variables scopes in Powershell.
If instead of using a variable declared at the begin of the script to hold the value of $OutputPath I use a literal string then it works. Otherwise, it complains that the value is null at runtime (In Powershell ISE it shows a value)
So, the action block now looks like this:
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
Expand-Archive -LiteralPath $FullPath -DestinationPath "C:\Temp"
Remove-Item -LiteralPath "$FullPath" -Force
}
catch [System.SystemException]
{
Write-Host $_
}
}
I would prefer to have all my vars at the begin, so they can be easily changed if needed, but at least this version works.

Powershell Scipt Runs in ISE only

I have researched this question quite a bit and have found others with similar issues, but no fix that works for us.
We have built a power shell script to monitor a folder for new images, check their color profile with exiftool and convert when needed with image magick. All of this functionality works well enough when the script is run in ISE, but will not work if the script is executed from a .exe or ran manually.
I have read that FileSystemWatcher requires the script be ran in STA which I have attempted to do a few times by including -STA in the target for the .exe shortcut. Doing so proves unsuccessful.
#----------------------------------------------------------------------------
Unregister-Event -SourceIdentifier FileCreated
Clear
#----------------------------------------------------------------------------
$description = Get-WmiObject -Class Win32_OperatingSystem |Select Description
$description = $description -Replace "#{Description=",""
$description = $description -Replace "}",""
$assetsFolder = "E:\" + $description + "\Capture One Session\Output"
$conversionStage = "C:\Profile_Pro\conversionStage"
#----------------------------------------------------------------------------
New-Item -ItemType directory -Force -Path "$assetsFolder" | Out-Null
New-Item -ItemType directory -Force -Path "$assetsFolder" | Out-Null
#----------------------------------------------------------------------------
$filter = "*.*"
$srgb = "sRGB IEC61966-2.1"
$isTif = "tif"
#----------------------------------------------------------------------------
$monitor = New-Object IO.FileSystemWatcher $assetsFolder, $filter -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
#----------------------------------------------------------------------------
$onCreated = Register-ObjectEvent $monitor Created -SourceIdentifier FileCreated -Action {
#----------------------------------------------------------------------------
Add-Type -AssemblyName System.Windows.Forms
#----------------------------------------------------------------------------
$path = $event.SourceEventArgs.FullPath
$name = $event.SourceEventArgs.Name
Write-Host $path
Write-Host $name
If ($name -Match $isTif)
{
$BOX = [System.Windows.Forms.MessageBox]::Show('TIFF FILE DETECTED. PLEASE CHECK RECIPE.', 'Warning', 'ok', 'Warning')
$path = $path -Replace ".tif.tmp",".tif"
Start-Sleep -s 2
Remove-Item "$path" -Force
}
Else
{
$colorSpace = C:\Profile_Pro\tools\exiftool.exe -T -ProfileDescription $path
$profileConvert = 'C:\Profile_Pro\tools\sRGB_Color_Space_Profile.icm'
If ($colorSpace -Match $srgb)
{
}
Else
{
Start-Sleep -s 3
$name = $name -Replace ".jpg.tmp",".jpg"
$path = $path -Replace ".jpg.tmp",".jpg"
Move-Item -Path $path -Destination $conversionStage -Force
convert $conversionStage\$name -profile $profileConvert $path
Start-Sleep -s 1
Remove-Item "$conversionStage\$name" -Force
#----------------------------------------------------------------------------
$BOX = [System.Windows.Forms.MessageBox]::Show('COLOR PROFILE ERROR. PLEASE CHECK RECIPE.', 'Warning', 'ok', 'Warning')
#----------------------------------------------------------------------------
$TO = $env:USERNAME + "#biz.com"
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = $TO
$Mail.Subject = "COLOR PROFILE DEFECT: " + $name
$Mail.importance = 2
$Mail.Body = "A COLOR PROFILE DEFECT HAS BEEN DETECTED WITH FILE:`r`n`r`n$name`r`n`r`nTHIS FILE IS FIXED.`r`n`r`nPLEASE CHECK YOUR PROCESS RECIPE."
$Mail.Send()
}
}
}
#----------------------------------------------------------------------------
#Unregister-Event -SourceIdentifier FileCreated
#----------------------------------------------------------------------------
Any ideas to keep this script running as a .exe or outside of ISE would be greatly appreciated.

Remove-Item cmdlet not working properly

So I have a script that combs through a directory of about 1200 songs, the user selects one song, (which is then put into the $Selected variable) and then through "script magic" (I can provide the code if necessary, but I don't think it is for our purposes) an email is sent to an email account I need it sent to. I then want to delete the song from the directory aaaannnnndddd that is when I run into issues. Here is the code I originally tried to delete the song with:
Remove-Item C:\Users\woafr\Desktop\Songs\$Selected -recurse -force
And with that code I got hit with this error message:
Remove-Item : Cannot remove item C:\Users\woafr\Desktop\Songs\song.mp3: The process cannot access the file C:\Users\woafr\Desktop\Songs\song.mp3' because it is being used by another process
So I then read this artice and this Stack Overflow thread and this Server Fault thread and modified my code to this:
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
And still got hit with the same errors. Is there something I can do here that will have me delete the songs, or will I have to do it by hand (the horror!)
Here is the whole script for reference:
# Search Engine part
$SearchInput = Read-Host "Enter song name here:"
$Items = Get-ChildItem C:\Users\woafr\Desktop\Songs -Recurse -Filter *$SearchInput*
IF (-Not $Items)
{Write-Host 'Nothing returned...
The search engine does not care about capitilization (so "That" and "that" are read the exact same by the search engine)
But it does care about punctuation (so "That''s" and "Thats" are not read the same by the search engine). Try Again' -ForegroundColor Red}
# Choose you this day what song you want
IF (-Not $Items)
{cmd /c pause}
$Index = 1
$Count = $Items.Count
foreach ($Item in $Items) {
$Item | Add-Member -MemberType NoteProperty -Name "Index" -Value $Index
$Index++
}
$Items | Select-Object Index, Attributes, LastWriteTime, Name | Out-Host
$Input = Read-Host "Select an item by index number, then press enter (1 to $Count)"
$Selected = $Items[$Input - 1]
Write-Host "You have selected $Selected"
# Email account the script is sending from
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "myemail#gmail.com"
$Password = "mypassword"
# Email the script is sending
$to = "emailtoingest#gmail.com"
$subject = "Songs To Ingest"
$body = "Ingest attachment into WideOrbit"
$attachment = New-Object System.Net.Mail.Attachment("C:\Users\woafr\Desktop\Songs\$Selected")
$attachment.ContentDisposition.FileName = "$Selected"
# Act of sending the email
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.from = $username
$message.attachments.add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent" -ForegroundColor Green
cmd /c pause
# Trying to delete the damn thing
Get-ChildItem C:\Users\woafr\Desktop\Songs\$Selected -recurse -force | Remove-Item
cmd /c pause
So the problem is send mail objects are locking the file ,try using this snippet just before your remove-item commandlet:
$smtp = $null
foreach ($attachment in $message.attachments){
$attachment.dispose();
}
$message.dispose();

Powershell variable getting "lost"

I'm working on a script that monitors an error folder and sends e-mail when an error occurs. For each error we get two files in the folder, one text file and one xml. In the e-mail I want to include the entire content of the text file and part of the content of the xml file.
In the following script I get only the content of the text file. (Lines for sending the email are commented out for testing purposes). I have read about variables and foreach and I guess this may be the problem, but I'm still not sure how to fix this in my script. Or maybe there is a much easier way to do this?
$Foldertowatch = 'C:\lpos\invalidArts'
$FilterXML = '*.xml'
$FilterTXT = '*.txt'
Unregister-Event -SourceIdentifier CreatedEventXML
$fswXML = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterXML
$fswXML.EnableRaisingEvents=$true
$fswXML.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
$user.RetailStoreID
$user.WorkStationID
$user.OperatorID
$user.SequenceNumber
}
}
Unregister-Event -SourceIdentifier CreatedEventTXT
$fswTXT = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterTXT
$fswTXT.EnableRaisingEvents=$true
$fswTXT.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswTXT -EventName Created -SourceIdentifier CreatedEventTXT -Action {
$FilenameTXT = $Event.SourceEventArgs.Name
$ContentTXT = (Get-Content $Foldertowatch\$FilenameTXT) -join "`n"
write-host $user.retailstoreid
Write-Host $contenttxt
<#$From = "from#mail.com"
$To = "to#mail.com"
$SMTPServer = "mailserver.com"
$subject = $env:COMPUTERNAME + " contains invalid ARTSXML"#>
<#Write-Host "Store:" + $ContentXML.RetailStoreID + "`n" + "Workstation:" + $ContentXML.WorkStationID + "`n" +"Operator:" + $ContentXML.OperatorID + "`n" +"Receiptnumber:" + $ContentXML.sequencenumber + "`n" + "`n" + "Filelocation: $Foldertowatch\$FilenameTXT" + "`n" + "`n" + <#$ContentTXT##>
<#$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer);
$smtp.Send($From, $To, $subject, $body);#>
}
The $ContentXML is from an early try, it should be $user now.
I manage to get content from XML if I run first part of script like this:
$Foldertowatch = 'C:\lpos\invalidArts' <# Folder to watch #>
$FilterXML = '*.xml' <# Use *.xml #>
$FilterTXT = '*.txt' <# Use *.txt for poslog2arts, use *.log for POS Reporting #>
Unregister-Event -SourceIdentifier CreatedEventXML
$fswXML = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterXML
$fswXML.EnableRaisingEvents=$true
$fswXML.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
write-host $user.RetailStoreID
write-host $user.WorkStationID
write-host $user.OperatorID
write-hosts $user.SequenceNumber
}
}
I'm not sure of your intent, but I see a possible solutions. First, this code:
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
$user.RetailStoreID
$user.WorkStationID
$user.OperatorID
$user.SequenceNumber
}
You never seem to use $XMLtmp again. Also, it's just going to contain an array of strings, not something that has properties like $user.RetailStoreID
What you can do is this:
$users = #()
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
foreach ($user in $XMLFile.POSLog.POSLogTransaction) {
$users += $user
}
}
Then later you can index that array. Are there more than one user? Do you want to send more than one email?
At that point you can do the following:
$users | % { Write-Host $_.RetailStoreId }
The $user variable you create in the foreach () {} goes out of scope (aka "disappears") when the } is hit. The $XMLtmp is unnecessary. Declaring $users outside of the scope of the Action and foreach ensures it is global to the entire script.