Powershell - When watching folder for new file created - if statement inside "Register-ObjectEvent" is not firing - powershell

Goal: File watcher watches the staging folder for new files. If the new file name contains "JDE_Reimb" then move the file into another folder "$reimb_jde_path" ,also renaming the new file.
Issue: The If statement is not firing me at all. Up to creating the $fullpath works, but my If statement is not executing. Any ideas why? Also I need to watch this folder for 2 other file which contain specific string in the file name. What is the best way to accomplish this in one script?
$reimbFile = "JDE_Reimb"
$reimb_jde_path = "\\rootfolder\reimbfolder"
$staging_folder_path = "\\rootfolder\stagingfolder\" #"
$filter = "*.txt"
$watcherCRExport_Staging = New-Object IO.FileSystemWatcher $staging_folder_path, $filter -Property #{
IncludeSubdirectories = $false
}
Register-ObjectEvent $watcherCRExport_Staging Created -SourceIdentifier foldertest -Action {
$text = $eventArgs.Name
Write-Host $text# Write-Host $eventArgs.ChangeType
$fullpath = Join-Path -Path $staging_file_path -ChildPath $text# Write-Host "Full path is: $fullpath"
If($text.Contains($reimbFile)) {
$newtext = $text.Substring(0, $text.IndexOf("_") + 1 + $text.Substring($text.IndexOf("_") + 1).IndexOf("_"))# Write-Host "Created: $($newtext)"
$newfilename = $newtext + ".txt"
$nextpath = Join-Path -Path $reimb_jde_path -ChildPath $newtext
Copy-Item-Path $fullpath -Destination $nextpath
Write-Host "---------------------------------"
Write-Host $newfilename
Write-Host $fullpath
Write-Host $nextpath
Write-Host "Reimbursement Done copying"
Write-Host "---------------------------------"
}
Else {
Write-Host "No Match!"
}
}

Related

How to run powershell cmdlets one after the other

I have a sharepoint 2010 list designed with custom solution. It has 3 level folder hierarchy. In the last folder level multiple documents are present as attachments. I want to get all the document attachments from that folder and store it in my local drive, so that it can be migrated to a different platform.
Number of Attachments are around 350000.
My Tasks are:
Creating Folder in my drive.
Getting Attachment ids and create folder with id name, as inputs from a txt file.
Map network drive
Copy attachment from network drive to local folder.
Delete network drive.
These 5 steps are to be repeated for around 350000 attachments.
Kindly let me know if cmdlets can be executed properly one after the other.
$idsFile = "H:\D\Temp\testingid.txt"
$FileStore = "H:\D\Temp\Attachments"
foreach ($line in Get-Content $idsFile) {
$FileCount = 1
$thisappid = $line.Split("`t")
Write-Host $thisappid.GetValue(0)
$FPath = $FileStore + '/' + $thisappid.GetValue(1)
Write-Host $FPath
if (!(Test-Path $FPath)) {
Write-Host "Creating folder.."
$F1 = New-Item -Path $FileStore -Name $thisappid.GetValue(1) -ItemType "directory"
Write-Host $F1
$F2 = New-Item -Path $F1 -Name $thisappid.GetValue(0) -ItemType "directory"
} else {
Write-Host "Folder" $thisappid.GetValue(1) "Already exists"
$SPath = $FileStore + '/' + $thisappid.GetValue(1) + '/' + $thisappid.GetValue(0)
Write-Host $SPath
if (!(Test-Path $SPath)) {
$F2 = New-Item -Path $SPath -Name $thisappid.GetValue(0) -ItemType "directory"
Write-Host $F2
} else {
Write-Host "Folder" $thisappid.GetValue(0) "already exists"
Write-Host "Move to Next.."
}
}
Write-Host $thisappid.GetValue(0)
$id = $thisappid.GetValue(0) -as [int]
Write-Host $id
Write-Host $id.GetType()
net use Y: \\domainName/sites/SiteName/Lists/MyList/Attachments/$id
/Persistent:Yes
Start-Sleep -s 10
$name = Get-ChildItem -Path Y:\ -Name
Start-Sleep -s 10
Copy-Item -Path Y:\$name -Destination $dest
Start-Sleep -s 10
net use Y: /delete /y
Start-Sleep -s 10
$FileCount = $FileCount+1
Write-Host $FileCount
}

PowerShell Batch ConvertImage

I am working on a PowerShell function that will convert jpg to png. I got that to work. I cannot figure out how to get it to delete the original jpg file after finishing. I have attempted to use the del and remove command but cannot delete the original file because it is still being used in the process. I have also tried to end the process but it ended the whole process when I put it within the foreach loop. Is there a way to get it to end the process so the file can be deleted and then continue through the rest of the images? Below is the code that converts but does not delete. If there is a better way to do this I would like to know were I can improve. Thank you !
function ConvertImage{
param ([string]$path)
$path=Convert-Path . #path to files
if (Test-Path $path)
{
#Load required assemblies and get object reference
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
foreach($file in (ls "$path\*.jpg")){
$convertfile = new-object System.Drawing.Bitmap($file.Fullname)
$newfilname = ($file.Fullname -replace '([^.]).jpg','$1') + ".png"
$convertfile.Save($newfilname, "png")
$file.Fullname
}
}
else
{
Write-Host "Path not found."
}
};ConvertImage -path $args[0]
How Do I use an integer with leading zeroes for the code below:
function ConvertImage{
param ([string]$path)
$Name = Read-Host -Prompt 'Input new name'
$Start = Read-Host -Prompt 'Input start number'
$Ext1 = Read-Host -Prompt 'Input Initial Extension'
$Ext2 = Read-Host -Prompt 'Input Ending Extension'
Write-Host "You input '$Name' and '$Start'"
Write-Host "You input '$Ext1' and '$Ext2'"
$i = "{0:D2}" -f [int]$Start
Get-ChildItem ("*.$Ext1") | %{Rename-Item $_ -NewName ("$Name"+"_"+"$i.$Ext1" -f $i++)}
Get-ChildItem ("*.$Ext2") | %{Rename-Item $_ -NewName ("$Name"+"_"+"$i.$Ext2" -f $i++)}
$path=Convert-Path . #path to files
if (Test-Path $path)
{
#Load required assemblies and get object reference
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
foreach($file in (ls "$path\*.$Ext1")){
$convertfile = new-object System.Drawing.Bitmap($file.Fullname)
$newfilname = ($file.Fullname -replace "([^.]).$Ext1",'$1') + (".$Ext2")
$convertfile.Save($newfilname, "$Ext2")
$file.Fullname
# Dispose file to stop using it
$convertfile.dispose()
# In brackets in the event that the filepath has a space
Remove-Item "$($file.Fullname)"
}
}
else
{
Write-Host "Path not found."
}
};ConvertImage -path $args[0]
Just do a Remove-Item at the end of your foreach.
function ConvertImage{
param ([string]$path)
$path=Convert-Path . #path to files
if (Test-Path $path)
{
#Load required assemblies and get object reference
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
foreach($file in (ls "$path\*.jpg")){
$convertfile = new-object System.Drawing.Bitmap($file.Fullname)
$newfilname = ($file.Fullname -replace '([^.]).jpg','$1') + ".png"
$convertfile.Save($newfilname, "png")
$file.Fullname
# Dispose file to stop using it
$convertfile.dispose()
# In brackets in the event that the filepath has a space
Remove-Item "$($file.Fullname)"
}
}
else
{
Write-Host "Path not found."
}
};ConvertImage -path $args[0]

Powershell script executed on each file in a folder?

I currently have a powershell script, which print out some information regarding the files which passed in as argument..
The command for executing the script, it done as such:
.\myscript.ps1 -accessitem C:\folder
I want to apply the script on all files and folder on the drive C:, is it possible i for loop to list all files, and pass the path as argument for the script?
The script:
[CmdletBinding()]
Param (
[Parameter(Mandatory=$True,Position=0)]
[String]$AccessItem
)
$ErrorActionPreference = "SilentlyContinue"
If ($Error) {
$Error.Clear()
}
$RepPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$RepPath = $RepPath.Trim()
$str = $AccessItem -replace ':',''
$str = $AccessItem -replace '/','.'
$FinalReport = "$RepPath\"+$str+".csv"
$ReportFile1 = "$RepPath\NTFSPermission_Report.txt"
If (!(Test-Path $AccessItem)) {
Write-Host
Write-Host "`t Item $AccessItem Not Found." -ForegroundColor "Yellow"
Write-Host
}
Else {
If (Test-Path $FinalReport) {
Remove-Item $FinalReport
}
If (Test-Path $ReportFile1) {
Remove-Item $ReportFile1
}
Write-Host
Write-Host "`t Working. Please wait ... " -ForegroundColor "Yellow"
Write-Host
## -- Create The Report File
$ObjFSO = New-Object -ComObject Scripting.FileSystemObject
$ObjFile = $ObjFSO.CreateTextFile($ReportFile1, $True)
$ObjFile.Write("NTFS Permission Set On -- $AccessItem `r`n")
$ObjFile.Close()
$ObjFile = $ObjFSO.CreateTextFile($FinalReport, $True)
$ObjFile.Close()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ObjFSO) | Out-Null
Remove-Variable ObjFile
Remove-Variable ObjFSO
If((Get-Item $AccessItem).PSIsContainer -EQ $True) {
$Result = "ItemType -- Folder"
}
Else {
$Result = "ItemType -- File"
}
$DT = Get-Date -Format F
Add-Content $ReportFile1 -Value ("Report Created As On $DT")
Add-Content $ReportFile1 "=================================================================="
$Owner = (Get-Item -LiteralPath $AccessItem).GetAccessControl() | Select Owner
$Owner = $($Owner.Owner)
$Result = "$Result `t Owner -- $Owner"
Add-Content $ReportFile1 "$Result `n"
(Get-Item -LiteralPath $AccessItem).GetAccessControl() | Select * -Expand Access | Select IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags, PropagationFlags | Export-CSV -Path "$RepPath\NTFSPermission_Report2.csv" -NoTypeInformation
Add-Content $FinalReport -Value (Get-Content $ReportFile1)
Add-Content $FinalReport -Value (Get-Content "$RepPath\NTFSPermission_Report2.csv")
Remove-Item $ReportFile1
Remove-Item "$RepPath\NTFSPermission_Report2.csv"
Invoke-Item $FinalReport
}
If ($Error) {
$Error.Clear()
}
I would prefer a outside command doing this, as workings of the script should not be altered, it it used for single file testing..
There are two ways to do this:
Add -Recurse Flag to the script
Run the script on each directory
I'm going with option two since the script looks complicated enough that I don't want to touch it.
$path_to_script = "C:\path\to\myscript.ps1"
$start_directory = "C:\folder"
# Call Script on Parent Directory
& "$path_to_script" -AccessItem "$start_directory"
# Call Script on any Child Directories within the "$start_directory"
foreach($child in (ls "$start_directory" -Recurse -Directory))
{
$path = $child.FullName
& "$path_to_script" -AccessItem "$path"
}
Basically, I'm calling the script on the parent directory and any sub-directories within the parent directory.

How can I run an MSBuild task in Powershell on file changed

I am trying to write something like a CSharp watch task in PowerShell. So, what I want to happen is when a CSharp file changes in a certain directory, it tries to find the csproj file and initiates a build.
Here's what I have currently
function Watch-CSharp-Files() {
set-location "D:\path\to\csharp\files\"
$originalPath = Get-Location
Write-host "Welcome to The Watcher. It keeps track of changing files in this solution directory (including subdirectories) and triggers a build when something changes..."
$existingEvents = get-eventsubscriber
foreach ($item in $existingEvents) {
Unregister-event -SubscriptionId $item.SubscriptionId
write-host "Unsubscribed existing event:" $item.Action.Name
}
$folder = get-location
$filter = '*.*'
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $watcher Changed -SourceIdentifier FileChanged -Action {
$path = $Event.SourceEventArgs.FullPath
if ($path -match "(\.cs~|.cs$)") {
write-host "file changed: $path"
Invoke-Expression -Command "Find-And-Build-Project '$path'"
}
}
}
function Find-And-Build-Project([string]$path) {
write-host "BUILD PROJECT REPORTING FOR DUTY"
$pathParts = "$path".Split("\\")
$end = $pathParts.Count - 2 # skip the file name to the parent directory
$testPath = $pathParts[0..$end] -join "\"
write-host "testing path $testPath"
$csproj = Get-ChildItem -path $testPath *.csproj
For ($i = 0; $i -le 10; $i++) {
$newEnd = $end - $i
$newPath = $pathParts[0..$newEnd] -join "\"
$csproj = Get-ChildItem -path $newPath *.csproj
write-host "$i. trying: $newPath, csproj: $csproj"
if ($csproj) {
write-host "found on $i, at $newPath, $csproj"
break
}
}
write-host "Ready: $newPath\$csproj"
$msbuild = "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe"
write-host "trying to MSBUILD"
& $msbuild ("$newPath\$csproj", "/target:Build", "/p:configuration=debug", "/verbosity:n")
}
Watch-CSharp-Files
What I have found is that within the function Find-And-Build-Project, the & $msbuild doesn't get invoked. But, I don't understand why.
Any ideas?
Ok, this helped me: https://stackoverflow.com/a/37724701/1326235.
This script targets the saved .cs file (or .cs~tmp[0-9].cs as Visual Studio seems to create), then searches back up the directory tree to find a .csproj file and builds it.
I published the module to the PowerShell Gallery, it's called CSharp-Watch

File system watcher Event when run using a script

Hi I have installed the PowerShellPack and I am using the FileSystem watcher module,but the problem when I safe the file as a script and execute it.
The problem is that if you execute the script it runs and the monitors the folder for changes but once the script stops (gets to the end of execution) the folder is no longer monitored.
I have tried to place everything in a do while loop but that does not seem to work.
PowerShellPack Install
Import-Module -Name FileSystem
$TempCopyFolder = "c:\test"
$PatchStorage = "c:\testpatch"
Start-FileSystemWatcher -File $TempCopyFolder -Do {
$SearchPath = $File
$PatchesPath = $PatchStorage
$NewFolderFullPath = "$($eventArgs.FullPath)"
$NewFolderName = "$($eventArgs.Name)"
$PathToCheck = "$PatchesPath\$NewFolderName"
#Check if it is a filde or folder
switch ($ObjectType)
{{((Test-Path $NewFolderFullPath -PathType Container) -eq $true)}{$ObjectType = 1;break}
{((Test-Path $NewFolderFullPath -PathType Leaf) -eq $true)}{$ObjectType = 2;break}}
# Its a folder so lets check if we have a folder in the $PatchesPath already
IF($ObjectType -eq 1){
IF(!(Test-Path -LiteralPath $PathToCheck -EA 0))
{
sleep -Seconds 3
#Make a new directory where we store the patches
New-item -Path $PatchesPath -Name $NewFolderName -ItemType directory
#Make a folde in the folder for TC1
$TcFolder=$NewFolderName + '_1'
$NewPatchesPath = "$PatchesPath\$NewFolderName"
New-item -path $NewPatchesPath -Name $TcFolder -ItemType directory
$CopySrc = $NewFolderFullPath
$CopyDes = "$NewPatchesPath\$TcFolder"
}
# There is a folder there so lets get the next number
Else{
$HighNumber = Get-ChildItem -Path $PathToCheck | select -Last 1
#Core_SpanishLoginAttemptsConfiguration_Patch_03
$NewNumber = [int](Select-String -InputObject $HighNumber.Name -Pattern "(\d\d|\d)" | % { $_.Matches } | % { $_.Value } )+1
$TcFolder= $NewFolderName + '_' + $NewNumber
$NewPatchesPath = "$PatchesPath\$NewFolderName"
$CopySrc = $NewFolderFullPath
$CopyDes = "$NewPatchesPath\$TcFolder"
}
#Lets copy the files to their new home now that we know where every thing goes
$robocopy = "robocopy.exe"
$arguments = '''' + $CopySrc + '''' +' '+ ''''+ $CopyDes + '''' + '/E'
Invoke-Expression -Command "$robocopy $arguments"
Do {sleep -Seconds 1;$p = Get-Process "robo*" -ErrorAction SilentlyContinue}
While($p -ne $null)
#Now lets check every thing copyed
$RefObj = Get-ChildItem -LiteralPath $NewFolderFullPath -Recurse
$DifObj = Get-ChildItem -LiteralPath $CopyDes -Recurse
IF(Compare-Object -ReferenceObject $RefObj -DifferenceObject $DifObj)
{write-host "Fail"}
Else{# Now lets delete the source
Remove-Item -LiteralPath $CopySrc -Force -Recurse
}
}}
You don't need add-on modules or WMI for this. Just set of the FileSystemWatcher yourself and register an event. Sure, it's a bit more code, but at least you know what's going on. :)
$watcher = new-object System.IO.FileSystemWatcher
$watcher.Path = 'c:\logs'
$watcher.Filter = '*.log' # whatever you need
$watcher.IncludeSubDirectories = $true # if needed
$watcher.EnableRaisingEvents = $true
Register-ObjectEvent $watcher -EventName Changed -SourceIdentifier 'Watcher' -Action { param($sender, $eventArgs)
<process event here>
}
When done:
Unregister-Event -SourceIdentifier 'Watcher'
This is something you probably need: Monitoring file creation using WMI and PowerEvents module
PowerEvents Module isn't mandatory if you know how to create Permanent Events in WMI. For more information on that, check my eBook on WQL via PowerShell: http://www.ravichaganti.com/blog/?page_id=2134