January 23, 201610 yr I'm looking to run a power shell script on my ritualized machine on a timer to include any new files I've added to my movies folder. I found a power shell script online that seems to work for the most part however, I'm not versed AT ALL in running such things. The main problem is that my movie library has sub folders. Since scanning recursively is not supported by handbrake yet I'd like to use this functionality until that feature is implemented. # If you get execution errors running a Powershell Script, start Powershell as Admin and execute the following "Set-ExecutionPolicy RemoteSigned" $TVShowsFolder = "" $MoviesFolder = "\\tower\Media\test\" $TVShowsBackupFolder = "" $MoviesBackupFolder = "z:\" $HandBrakeCLI = "C:\Program Files\Handbrake\HandBrakeCLI.exe" $HandBrakePreset = "ipad 3" "Starting TV Prox" "Checking for existing TV Prox" $Prox = Get-WmiObject Win32_Process -Filter "Name like '%powershell%'" | select-Object CommandLine | where {$_ -match "tvprox"} $Proxc = $Prox | measure if ($Proxc.Count -gt 1) { "We already have a running TV Prox .. exiting" exit } #Get a list of TV Shows and Movies that are not m4v or mp4. Update the extensions list below as necessary to include missed files. $TVShows = get-childitem $TVShowsFolder -include *.mkv,*.avi,*.mpeg,*.mpg -recurse | foreach ($_) { $_.fullname } | sort $Movies = get-childitem $MoviesFolder -include *.mkv,*.avi,*.mpeg,*.mpg -recurse | where {$_.length -ge 100MB} | foreach ($_) {$_.fullname} | sort "Processing TV Shows" foreach ($SourceFile in $TVShows) { "Processing: $SourceFile" $TargetFile = [io.path]::GetDirectoryName($SourceFile) + "\" + [io.path]::GetFileNameWithoutExtension($SourceFile) + ".m4v" "Create: $targetfile" & $HandBrakeCLI -i $SourceFile -o $TargetFile --preset=$HandBrakePreset $BackupFile = $SourceFile.Replace($TVShowsFolder, $TVShowsBackupFolder) "Backup: $BackupFile" New-Item -ItemType File -Path $BackupFile -Force Move-Item $SourceFile $BackupFile -Force } foreach ($SourceFile in $Movies) { "Processing: $SourceFile" $TargetFile = [io.path]::GetDirectoryName($SourceFile) + "\" + [io.path]::GetFileNameWithoutExtension($SourceFile) + ".m4v" "Create: $targetfile" & $HandBrakeCLI -i $SourceFile -o $TargetFile --preset=$HandBrakePreset $BackupFile = $SourceFile.Replace($MoviesFolder, $MoviesBackupFolder) "Backup: $BackupFile" New-Item -ItemType File -Path $BackupFile -Force } This is the script i'm currently trying to use. However, there are several things I'd like to change to optimize it for my purposes. 1. I'd like for when the script is ran to check the output folder to see if there are any new files added. And skip those already converted. 2. Unless i'm missing it. I'd like to set a destination folder. Basically the end goal is for me to not log into my server to start up any commands for this to run. All i want to do is add videos to my "movie" folder and an hour or so later have a perfectly converted copy in my "ipad" folder. Once again I don't know much about PS so any help will be greatly appreciated P.S. if I've put this in the wrong place sorry. I've been searching for what i want for a couple of hours. Edit: I found this script. Seems to be a bit more useful. However, I'm not sure about it moving any of my original files. # Script to Convert multiple files with handbrake, for individual movie files and series # Will recurse through a folder and convert the files to mp4 with handbrake # Will place them into a new location maintaining folder structure # Move the original converted files to a new location # Delete empty folders once files moved # Edit paths, file types and handbrake location as required. #Where we are looking for Files in folders $search="\\tower\Media\Test" #Root Folder for newly created mp4 files $newfolder="z:\" # Path to move completed original files to $donefiles="" #handbrake exe file $handbrake="c:\Program Files\HandBrake\handbrakecli.exe" #file type we are working on $ext="mkv" #handbrake preset $HBPreset="ipad" #End of Edit section #Search Paths $path=$search -replace "\\","\\" $donepath=$newfolder -replace "\\","\\" #todays date $date=get-date -format ddMMyy-HHmm #operations log $Logfile="$newfolder\$date-log.txt" # Get directorys $directorys=Get-ChildItem -Path $search -Recurse | Where-Object { $_.PSIsContainer } foreach ($item in $directorys) { "Searching - $item" | out-file $logfile -append # Search for files extention $TestP=$item.fullname+"\*.$ext" #test if any files of ext type in folder file there if (Test-Path $TestP) { "found $ext in $item" | out-file $logfile -append $a=$item.Fullname #create new directory variable for file in new location path $newdirectory = $a -replace $path,$newfolder "Create $newdirectory" | out-file $logfile -append #check if folder exits, if not make it if ((test-path $newdirectory) -ne $true) { new-item $newdirectory -itemtype directory } #get a list of the files $videofiles=@(get-childitem -path $item.fullname *.$ext) # execute the following on each file in folder foreach ($vid in $videofiles) { "Found File $vid" | out-file $logfile -append #get file name and path $b=$vid.Fullname #create a new filename with new path and rename file with .mp4 $newFileName = $b -replace $path,$newfolder $newFileName = $newFileName -replace "\.$ext$",".mp4" "New File Name $newfilename" | out-file $logfile -append get-date -format ddMMyy-HHmm | out-file $logfile -append # create a log for this file $HBLogfile="$newfolder\$date-$vid.name-log.txt" write-host "$vid Converting to $newfilename" # do the magic and convert using the present from old file to new one, write out a log of what handbrake does & $handbrake -i $vid.FullName -o $newFileName --preset $hbpreset 2>&1 | add-content -path $hblogfile get-date -format ddMMyy-HHmm | out-file $logfile -append #create new directory variable for file in new location path $newdirectorymove=$newdirectory -replace $donepath,$donefiles "Create $newdirectorymove" | out-file $logfile -append #check if folder exits, if not make it if ((test-path $newdirectorymove) -ne $true) { new-item $newdirectorymove -itemtype directory } #move the original file here write-host "$vid - Done Movingto $newdirectorymove" # move the item move-item -path $vid.fullname -destination $newdirectorymove $oldfile=$vid.fullname if ((get-childitem $vid.directory | measure ).count -eq 0) { remove-item $vid.directory } "Moved $oldfile to $newdirectorymove"| out-file $logfile -append } } } get-date -format ddMMyy-HHmm | out-file $logfile -append "----------------------" | out-file $logfile -append I was wondering if it would be possible for it to create/read a log file to keep track of what it has already copied. Also if anybody knows how to put a progress counter or bar or something that'd be great.
January 24, 201610 yr I have been wanting to do something very similar so I played around with this today. Hopefully, I will have some time to get it cleaned up and posted tomorrow.
January 24, 201610 yr Author Wow, that would be awesome. Sadly I lack the know how to do something like this. I mean I can manage simple things but totally reworking in a language I've never used is a different thing altogether.
January 24, 201610 yr It certainly isn't the prettiest script, but it works. I will probably work on it some more at some point. For instance, I would like to rename the output file so it has the proper video and audio codecs. You will need to setup a Preset in Handbrake called "iPad". Let me know if you have any questions. ### Set Variables $WatchFolder = "\\nas\BluRay" $OutputFolder = "E:\WatchFolder-Complete" $Logfile = "$outputFolder\HandBrake.log" ### Size Window and display Header $Host.UI.RawUI.WindowTitle = "HandBrake Watch Folder" $sizeWindow = new-object System.Management.Automation.Host.Size 120,50 $sizeBuffer = new-object System.Management.Automation.Host.Size 120,9999 if ($Host.UI.RawUI.WindowSize.width -gt 120) { $Host.UI.RawUI.WindowSize = $sizeWindow $Host.UI.RawUI.BufferSize = $sizeBuffer }else {$Host.UI.RawUI.BufferSize = $sizeBuffer $Host.UI.RawUI.WindowSize = $sizeWindow } #Title Write-Host "`n`n" #Long Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue #Blank Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue -nonewline Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue #Blank Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue -nonewline Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue #Text Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue -nonewline Write-Host " HandBrake Watch Folder " -ForegroundColor Yellow -nonewline Write-Host " " -BackgroundColor Blue #Blank Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue -nonewline Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue #Blank Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue -nonewline Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue #Long Line Write-Host " " -nonewline Write-Host " " -BackgroundColor Blue Write-Host "`n`n`n" Write-Host "Watch Folder:`t" -ForegroundColor White -NoNewline Write-Host $WatchFolder -ForegroundColor Magenta Write-Host "Output Folder:`t" -ForegroundColor White -NoNewline Write-Host $OutputFolder -ForegroundColor Magenta Write-Host "`nNote:`t" -ForegroundColor White -NoNewline Write-Host "This is single-threaded. It will not show the next file added until HandBrake has completed it's conversion of the previous file." -ForegroundColor Yello Write-Host "`n`n" ### Function to write text to log file function LogWrite { Param ([string]$logstring) Add-content $Logfile -value $logstring } ### Function for monitoring for Created, Deleted, Changed or Renamed Files ### from: https://github.com/sushihangover/SushiHangover-PowerShell/blob/master/modules/FileSystem/Start-FileSystemWatcher.ps1 function Start-FileSystemWatcher { <# .Synopsis Starts monitoring for file changes .Description Starts monitoring for file changes using the events on IO.FileSystemWatcher .Parameter File The Name of the File or Folder to Watcher .Parameter Filter The Filter of Files to Watch .Parameter Recurse If set, will watch the subdirectories of the folder as well as the folder .Parameter On A list of events to watch for. By default, Created, Deleted, Changed, and Renamed are watched for, and Error and Disposed are not watched for. .Parameter Do The script blocks to run when the event occurs .Example Get-Item $pwd | Start-FileSystemWatcher -includeSubdirectories # Starts a watcher on everything that changes beneath the current directory .Example Start-FileSystemWatcher \\MyServer\MyShare -do { $subject = "$($eventArgs.ChangeType): $($eventArgs.FullPath)" $body = (Get-Content $eventArgs.FullPath -errorAction SilentlyContinue | Out-String) $email = @{ From = '[email protected]' To = '[email protected]' SmtpServer = 'SmtpHost' Subject = $subject } if ($body) { $email+=@{Body = $body }} Send-MailMessage @email } # Watches \\MyServer\MyShare and sends an email with the content of files as they change #> param( [Parameter(ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)] [Alias('FullName')] [string]$File, [string]$Filter = "*", [switch]$Recurse, [ValidateScript({ if (-not ([iO.FileSystemWatcher].GetEvent($_))) { $possibleEvents = [iO.FileSystemWatcher].GetEvents() | ForEach-Object { $_.Name } throw "$_ is not an event on [iO.FileSystemWatcher]. Possible values are: $possibleEvents" } return $true })] [string[]] $On = @("Created", "Deleted", "Changed", "Renamed"), [scriptBlock[]] $Do ) process { $realItem =Get-Item $file -ErrorAction SilentlyContinue if (-not $realItem) { return } $watcher = New-Object IO.FileSystemWatcher -Property @{ Path = $realItem.Fullname Filter = $filter IncludeSubdirectories = $Recurse } foreach ($o in $on) { $null = Register-ObjectEvent $watcher $o foreach ($d in $do) { if (-not $d) { continue } $null = Register-ObjectEvent $watcher $o -Action $d } } } } ### Get Handbrake install path and shortname $handbrakeclipath = (Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Handbrake.exe" -erroraction silentlycontinue).'(Default)' -replace '.exe','cli.exe' $a = New-Object -ComObject Scripting.FileSystemObject $handbrakeclishortpath = $a.GetFile($handbrakeclipath).ShortPath ### Run Start-FileSystemWatcher ### Only looking for newly created files Start-FileSystemWatcher $WatchFolder -On Created -Filter "*.*" -Recurse -do { # Write new file name to console $File = Get-Item $($eventArgs.FullPath) $FilePath = $File.FullName $filename = $File.Name $BaseName = $File.BaseName $Extension = $File.Extension # Only process these extensions if ($extension -eq '.mkv' -or $extension -eq '.mp4' -or $extension -eq '.m4v' -or $extension -eq '.avi' -or $extension -eq '.wmv') { ### wait for file to be written do{ $a = "no error" try{ [iO.File]::OpenWrite($file).close(); } catch{ $a = "error" Start-Sleep 1 } }while($a -eq "error") #Write-Host "`n" # Write file name to PS Window $Now = Get-Date write-host "`nNew Movie Added: " -NoNewline write-host $file.FullName -ForegroundColor Green Write-Host " $now" # Output file name $OutFile = $OutputFolder + "\" + "iPad-" + $File.Name # Run Handbrake with 'iPad' preset [string]$handbrake = "cmd.exe /c start $handbrakeclishortpath -i `"$FilePath`" -o `"$OutFile`" --preset=`"iPad`"" Invoke-Expression $handbrake # Write original file name to log file $Now = Get-Date Logwrite "$now - $outfile" } }
January 24, 201610 yr And here is an XML file you can import to Task Scheduler to run it on system start. <?xml version="1.0" encoding="UTF-16"?> <Task version="1.3" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Date>2016-01-24T12:44:19.2704904</Date> <Author>DOMAIN\username</Author> <URI>\Handbrake Watch Folder</URI> </RegistrationInfo> <Triggers> <BootTrigger> <Enabled>true</Enabled> <Delay>PT5M</Delay> </BootTrigger> </Triggers> <Principals> <Principal id="Author"> <UserId></UserId> <LogonType>Password</LogonType> <RunLevel>HighestAvailable</RunLevel> </Principal> </Principals> <Settings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries> <AllowHardTerminate>false</AllowHardTerminate> <StartWhenAvailable>false</StartWhenAvailable> <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable> <IdleSettings> <StopOnIdleEnd>true</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <AllowStartOnDemand>true</AllowStartOnDemand> <Enabled>true</Enabled> <Hidden>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession> <UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>PT0S</ExecutionTimeLimit> <Priority>7</Priority> </Settings> <Actions Context="Author"> <Exec> <Command>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe</Command> <Arguments>-executionpolicy Unrestricted D:\scripts\FileSystemWatcher\FileSystemWatcher.PROD.ps1</Arguments> </Exec> </Actions> </Task>
January 25, 201610 yr Author wow!!! That's freaking awesome! I'll be giving it a go when I get a chance to. Now this create a list of jobs that it has already completed? as well does it move or do any kinds of alterations of the original files? Edit: I also have trailer files that are trailer.mkv how would I tell this script to exclude those files? I would like to rename the output file so it has the proper video and audio codecs. That sounds absolutly amazing here. Also is there any way to possibly add the ability to insert meta data like http://www.danhinsley.com/ does?
January 25, 201610 yr wow!!! That's freaking awesome! I'll be giving it a go when I get a chance to. Now this create a list of jobs that it has already completed? as well does it move or do any kinds of alterations of the original files? Edit: I also have trailer files that are trailer.mkv how would I tell this script to exclude those files? Yes, it creates a very simple log file in the target directory. It does not change any of the original files. I forgot about trailers...thats a pretty simple exclusion. Ill update the post tomorrow.
January 25, 201610 yr Author Darn, you replied before i could post about my question about Meta data http://www.danhinsley.com/ EDIT: ### Set Variables $WatchFolder = "\\tower\Media\test\" $OutputFolder = "F:\" This is the only bit I changed in the program. When i run it. Powershell opens and then just simply closes I'm running this from my laptop (with handbrake installed and the iPad preset) When i try to run i through the Powershell editor I get this error: cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170. + CategoryInfo : SecurityError: ( [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnauthorizedAccess I assume it's some sort of policy w/in the file its self. Edit: Edit: Okay I think I figured out the policy issue. Here--->https://technet.microsoft.com/en-us/library/ee176961.aspx However, i Now get this error: Exception setting "WindowSize": "The method or operation is not implemented." + $Host.UI.RawUI.WindowSize = $sizeWindow } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: ( [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting
January 25, 201610 yr Darn, you replied before i could post about my question about Meta data http://www.danhinsley.com/ EDIT: ### Set Variables $WatchFolder = "\\tower\Media\test\" $OutputFolder = "F:\" This is the only bit I changed in the program. When i run it. Powershell opens and then just simply closes I'm running this from my laptop (with handbrake installed and the iPad preset) When i try to run i through the Powershell editor I get this error: cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170. + CategoryInfo : SecurityError: ( [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnauthorizedAccess I assume it's some sort of policy w/in the file its self. Edit: Edit: Okay I think I figured out the policy issue. Here--->https://technet.microsoft.com/en-us/library/ee176961.aspx You probably already figured it out by now, but you need to set your Execution Policy to "Unrestricted". Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Confirm:$false However, i Now get this error: Exception setting "WindowSize": "The method or operation is not implemented." + $Host.UI.RawUI.WindowSize = $sizeWindow } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: ( [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting I'm about to post an updated file. Download that file, put it in a folder, go to a command prompt and type: PowerShell.exe -File "<pathtofile>\myscript.ps1"
January 25, 201610 yr Here is an updated version of the script. It excludes trailers either by looking for "trailer" in the name, and it also excludes files under 500MB (since movie files are rarely that small). FileSystemWatcher.v1.1.ps1.txt
January 25, 201610 yr Author PS C:\Users\user> PowerShell.exe -File "c:\FileSystemWatcher.v1.1.ps1" HandBrake Watch Folder Watch Folder: \\tower\Media\test\ Output Folder: \\tower\Media\test\ Note: This is single-threaded. It will not show the next file added until HandBrake has completed it's conversion of t he previous file. PS C:\Users\user> This is all I get when I run this. It just seems to stop there. EDIT: When I run it through the Powershell editor i get this error: + $Host.UI.RawUI.WindowSize = $sizeWindow } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: ( [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting
January 25, 201610 yr PS C:\Users\user> PowerShell.exe -File "c:\FileSystemWatcher.v1.1.ps1" HandBrake Watch Folder Watch Folder: \\tower\Media\test\ Output Folder: \\tower\Media\test\ Note: This is single-threaded. It will not show the next file added until HandBrake has completed it's conversion of t he previous file. PS C:\Users\user> This is all I get when I run this. It just seems to stop there. Did you actually copy a file to the folder after you ran the script?
January 25, 201610 yr There are already files in that folder. That not what you asked for. You asked for a script that will trigger an action to a file being copied to a share.
January 26, 201610 yr Author Okay, apparently I'm doing something wrong. I made an empty folder. I then plugged in the folder's location into the Powershell script. I then placed the powershell script on the C:\ Drive. I then Added the schedule to the system. I did change the target location of the powershell script. I rebooted the VM. Ran the script (right clicked on the script and ran Powershell). Also ran through CMD. I placed a new Video into that folder. Nothing happened after that. Either way through Powershell or CMD both just open and close almost instantly. I assume it's supposed to stay open in order to "Monitor" the folder. This is the only bit of code of the PS1 script I changed. $WatchFolder = "\\tower\Media\test\" $OutputFolder = "\\tower\Media\test\" I'm sorry for being a pain.
January 26, 201610 yr Ok...you need to crawl before you can run! You need to run it interactively first, before letting it run automatically. 1) RDP into the VM (or launch the console) 2) Launch the powershell script. 3) Copy a file to the source folder (that meets the qualifications - must be am mp4, mkv, m4v or avi, must be more than 500MB in size, and must not have 'trailer' in the name) 3a) You may also want to try a LOCAL directory, instead of a share. I'm running XFS on my unraid drives. I have no idea if it will work on BTRFS or RFS. 4) see what happens I have only tested this on PowerShell 4.0. I have no idea if it will run properly on 2.0 or 3.0. I have tested it on my main Windows 10 workstation, and a Windows Server 2012 R2 VM.
January 26, 201610 yr Author Okay but back to my original question. Should the PowerShell window stay open or does the window just close and run in the background? If it is supposed to stay open, it is not doing that. It immediately closes when I right click and run it. The only thing I change in the file is the directories that it is supposed to be watching. EDIT: Tested on my local machine: No luck. Any time I edit the ### Set Variables Section it seems to break the script. I've tried many different variables. I've tried pathing the script to the C:\ Drive. To a network share. To a mapped network share (Z:\ Drive). Every time I change any variable the script just runs and then instantly closes. If I leave the ### Set Variables section to the $WatchFolder = "\\nas\BluRay" $OutputFolder = "E:\WatchFolder-Complete" Which is the original format, PowerShell stays open (i assume looking for new files listed to those locations) I am running PowerShell Version: 5.0.10586.63 on windows 10. This is both on my VM and my local computer. Sorry for being a pain! If I right click the file and click Edit and use the intigrated PowerShell editor and click the run script button (F5) I get this error in the output window: PS F:\> F:\FileSystemWatcher.v1.1.ps1 Exception setting "WindowSize": "The method or operation is not implemented." At F:\FileSystemWatcher.v1.1.ps1:18 char:25 + $Host.UI.RawUI.WindowSize = $sizeWindow } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: ( [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting HandBrake Watch Folder Watch Folder: F:\Input-Folder Output Folder: F:\Output-Folder Note: This is single-threaded. It will not show the next file added until HandBrake has completed it's conversion of the previous file.
Archived
This topic is now archived and is closed to further replies.