I have a script (pasted below) that's supposed to do the following:
Loops and grabs all files that match a defined pattern
Copies those files into another location
Move the original source file into another location (if copy was successful)
It's doing step #1 and #2 but step #3, Move-Item is not moving any files and I don't know why and I get no indication of an error
Can someone help? Thanks
$source = "C:\Users\Tom\"
$source_move = "C:\Users\Tom\OldLogBackup1\"
$destination ="C:\Users\Tom\Mirror\"
if(-not(Test-Path $destination)){mkdir $destination | out-null}
ForEach ($sourcefile In $(Get-ChildItem $source | Where-Object { $_.Name -match "Daily_Reviews\[\d\d\d\d-\d\d\d\d\].journal" }))
{
#escape filename because there are brackets in the name!
$src = [Management.Automation.WildcardPattern]::Escape($sourcefile)
Copy-Item $src $destination
### Check for a successful file copy
if($?)
{
####
if(-not(Test-Path $source_move)){
echo "Path does not exist!"
} else {
echo "Path exists!"
### Move original source file someplace else
Move-Item $source_move$sourcefile $source_move
if($?)
{
echo "Source file successfully moved"
} else {
echo "Source file was not successfully moved"
}
}
}
Try along with the -force option.
The line Move-Item $source_move$sourcefile $source_move is moving the $sourcefile in the $source_move directory to the $source_move directory, which does nothing. I am guessing you meant to do Move-Item $source$sourcefile $source_move, or Move-Item $src $source_move.
Also, echo is simply an alias for Write-Output, which returns the argument to the caller. You can achieve the same result without the echo (any object on its own will be returned). Or, if you intended to use these as debug statements, you could use Write-Debug or Write-Host.
Related
I just want to know how to convert an images folder into a CBZ file READABLE for my Ebook (I checked the ebook and she can read this format).
Optimally, I would like to convert it without having to install everything. Just a script.
For those who are fast, I already answered my question... Just sharing it.
GO SEE UPDATE PART
Assuming your OS is Windows, we can do it with Batch or PowerShell.
For this one its process is quite easy, we just need to understand that a CBZ file IS a ZIP file with images in it. So we will just:
zip with 7zip because for some reasons the files converted with WinRAR didn't worked in my Ebook (wasn't even in the library) ;
Change the extension from .zip to .cbz.
I'm only going to show the PowerShell one because the .bat script had known issues.
Architecture
Architecture of the directory
The architecture should be:
My first folder
first image
second image
My second folder
first image
second image
PowerShell
Here's the code from my "#_ImagesFolderToCBZ.ps1"
Clear-Host
# INPUT - Script folder path
$i = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
# 7Zip path
$7zipPath = "$env:ProgramFiles\7-Zip\7z.exe"
# A list of the path of the zipped files
$listOfZippedFiles = New-Object Collections.Generic.List[String]
$listOfZippedNames = New-Object Collections.Generic.List[String]
# Ask the user if we delete the folders after their conversion
$isSdel = Read-Host -Prompt "Do you want to delete the folders after conversion [Y/N]: "
# Get the files inside the INPUT path and forEach children
Get-ChildItem "$i" | ForEach-Object {
# Get the full path of the file
$pathFolder = $_.FullName
# If the path here is a folder
if (Test-Path -Path "$pathFolder" -PathType Container) {
# Set the alias
Set-Alias 7z $7zipPath
# If the user asked for deletion of folders
if ("Y" -eq $isSdel.ToUpper()) {
# Zip the content of the folder
7z a "$pathFolder.zip" "$pathFolder\*" -sdel | FIND "ing archive"
}
else {
# Zip the content of the folder
7z a "$pathFolder.zip" "$pathFolder\*" | FIND "ing archive"
}
# Add the file name into the list
$listOfZippedFiles.Add("$pathFolder.zip")
$listOfZippedNames.Add("$_.zip")
}
# If the user asked for deletion of folders
if ("Y" -eq $isSdel) {
# Remove the now blank folders
if( $_.psiscontainer -eq $true){
if((gci $_.FullName) -eq $null){
$_.FullName | Remove-Item -Force
}
}
}
}
# For each zipped file
foreach ($file in $listOfZippedFiles) {
# Change the extension to CBZ
$dest = [System.IO.Path]::ChangeExtension("$file",".cbz")
Move-Item -Path "$file" -Destination $dest -Force
}
# Write for the user
Write-Host "`r`n`r`nConverted:"
# Displaying the converted files by their names
foreach ($file in $listOfZippedNames) {
$newName = [System.IO.Path]::ChangeExtension("$file",".cbz")
Write-Host "-- $newName"
}
# Blank line
Write-Host ""
# Pause to let us see the result
Pause
Output
output
As we can see, the folder is sucessfully created AND without loops like : I have ZIP files in the root folder of the script and they are also renamed into CBZ ones (I had this loop for my batch script).
I also added the choice to automatically delete the converted folders OR not.
Obviously, there's room for improvements (especially in how we delete the folders). I'll gladly take any advice.
UPDATE
I updated my script and it's much better. Less instructions, a list (in the prompt) that update itself when each folder is really converted. So no more: 1) ZIP all folders 2) rename their extension.
So a code that's more logic and also useful to show a beautiful process in real time.
Here's the updated code :
Clear-Host
# ROOT - Script folder path
$root = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
# 7Zip path
$7zipPath = "$env:ProgramFiles\7-Zip\7z.exe"
# Test if 7zip is installed
if (-not (Test-Path -Path $7zipPath -PathType Leaf)) {
throw "7 zip file '$7zipPath' not found"
}
# Ask the user if we delete the folders after their conversion
$isSdel = Read-Host -Prompt "Do you want to delete the folders after conversion [Y/N]: "
# Write for the user
Write-Host "`r`nConverted:"
# Get the files inside the INPUT path and forEach children
Get-ChildItem "$root" | ForEach-Object {
# Get the full path of the file
$pathFolder = $_.FullName
# If the path here is a folder
if (Test-Path -Path "$pathFolder" -PathType Container) {
# If the user asked for deletion of folders
if ("Y" -eq $isSdel.ToUpper()) {
# Zip the content of the folder while deleting the files zipped
& $7zipPath a "$pathFolder.zip" "$pathFolder\*" -sdel > $null
# Remove the now blank folder
if( $_.psiscontainer -eq $true){
if((gci $_.FullName) -eq $null){
$_.FullName | Remove-Item -Force
}
}
}
else {
# Zip the content of the folder
& $7zipPath a "$pathFolder.zip" "$pathFolder\*" > $null
}
# Change the extension to CBZ
$newName = [System.IO.Path]::ChangeExtension("$pathFolder.zip",".cbz")
Move-Item -Path "$pathFolder.zip" -Destination $newName -Force
# Tells the user this one is finished converting
Write-Host "--" -ForegroundColor DarkGray -NoNewline
Write-Host " $_.cbz"
}
}
# Tells the user it's finished
Write-Host "`r`nFinished`r`n" -ForegroundColor Green
# Pause to let us see the result
Pause
UPDATE 2
I made a GitHub project for this one. The URL is here:
https://github.com/PonyLucky/CBZ-Manga-Creator.
I have Several zip files that Contain multiple filetypes. The ONLY ones I am interested in are the .txt files. I need to extract the .txt files only and place them in a folder of their own, ignoring all other file types in the zips files.
All the zip files are in the same folder.
Example
-foo.zip
--1.aaa
--2.bbb
--3.ccc
--4.txt
-foo2.zip
--5.aaa
--6.bbb
--7.ccc
--8.txt
I want to have 4.txt and 8.txt extracted to another folder. I can't for the life of my figure it out and spent ages looking, googling and trying. Even managing to delete to zips once in a while :-)
Thanks in advance
Use the ZipArchive type to programmatically inspect the archive before extracting:
Add-Type -AssemblyName System.IO.Compression
$destination = "C:\destination\folder"
# Locate zip file
$zipFile = Get-Item C:\path\to\file.zip
# Open a read-only file stream
$zipFileStream = $zipFile.OpenRead()
# Instantiate ZipArchive
$zipArchive = [System.IO.Compression.ZipArchive]::new($zipFileStream)
# Iterate over all entries and pick the ones you like
foreach($entry in $zipArchive.Entries){
if($entry.Name -like '*.txt'){
# Create new file on disk, open writable stream
$targetFileStream = $(
New-Item -Path $destination -Name $entry.Name -ItemType File
).OpenWrite()
# Open stream to compressed file, copy to new file stream
$entryStream = $entry.Open()
$entryStream.BaseStream.CopyTo($targetFileStream)
# Clean up
$targetFileStream,$entryStream |ForEach-Object Dispose
}
}
# Clean up
$zipArchive,$zipFileStream |ForEach-Object Dispose
Repeat for each zip file.
Note that the code above has very minimal error-handling, and is to be read as an example
Try this:
Set-Location "Extraction path"
#("full path of foo.zip","full path of foo2.zip") | ForEach {
& "Full path of 7z.exe" x '-i!*.txt' $_.FullName
}
Sets location to the path where files will be extracted.
Passes a array of zip files to for loop.
Exexute 7z command to extract only zip files.
Here is one approach:
Go through each .zip file in a folder.
Extract archive into separate folder.
Extract .txt file from folder.
Copy files into destination folder containing all .txt files. This will overwrite files if they already exist in the destination folder.
Cleanup extracted folders once finished.
Demo:
function Copy-ZipArchiveFiles {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[ValidateScript({
if (-not(Test-Path $_ -PathType Container))
{
throw "The source path $_ does not exist. Please enter a valid source path."
}
else
{
$true
}
})]
[string]$Path,
[Parameter(Mandatory=$true)]
[ValidateScript({
if ([string]::IsNullOrEmpty($_.Trim()))
{
throw "The Destination path is null or empty. Please enter a valid destination path."
}
else
{
$true
}
})]
[string]$Destination,
[Parameter(Mandatory=$false)]
[AllowNull()]
[AllowEmptyString()]
[AllowEmptyCollection()]
[string[]]$Include
)
# Create destination folder if it doesn't already exist
if (-not(Test-Path -Path $Destination -PathType Container))
{
try
{
New-Item -Path $Destination -ItemType Directory -ErrorAction Stop
}
catch
{
throw "The destination path $Destination is invalid. Please enter a valid destination path."
}
}
# Go through each .zip file
foreach ($zipFile in Get-ChildItem -Path $Path -Filter *.zip)
{
# Get folder name from zip file w/o .zip at the end
$zipFolder = Split-Path $zipFile -LeafBase
# Get full folder path
$folderPath = Join-Path -Path $Path -ChildPath $zipFolder
# Expand .zip file into folder if it doesn't exist
if (-not(Test-Path -Path $folderPath -PathType Container))
{
Expand-Archive -Path $zipFile.FullName -DestinationPath $folderPath
}
# Copy files into destination folder
foreach ($file in Get-ChildItem $folderPath -Include $Include -Recurse)
{
Copy-Item -Path $file.FullName -Destination $Destination
}
# Delete extracted folders
Remove-Item -Path $folderPath -Recurse -Force
}
}
Usage:
Copy-ZipArchiveFiles `
-Path "C:\path\to\zip\files" `
-Destination "C:\path\to\text\files" `
-Include "*.txt"
Note: Could also use this for multiple extension types as well by passing -Include *.txt, *.pdf. I also went a bit overboard in the parameter error checking, but I believe in writing robust code. Good habit to get into when writing your own cmdlets anyways :)
I have written a script to get system variables and copy of several folders ,I wanted to create a directory for copy of several folders,to prevent duplication of folders we wanted a check condition so each time we run the script it is not creating folders. Like an example
$nfle=New-Item -ItemType "Directory" -Path "D:\Temp\" -Name "foo"
[bool]$checkfle=Test-Path "D:\Temp\foo" -PathType Any
if ( $checkfle -eq $True)
{
Write-Output "$nfle Exists"
}
else
{
$bnfle=New-Item -ItemType "Directory" -Path "D:\Temp\" -Name ("boo")
}
$cpypste=Copy-Item "D:\Temp\foo" -destination "D:\Temp\boo"
Write-Host "Succesful Copy of Folders"
So when we run the script it is creating folder foo,again when we run the script , it is displaying foo exists, and stopping the script is not going to next line, not even displaying the message.Is there a way in powershell to find out why the script is stopping or shall i add more information statements. TIA
It best to start with test-path to see if the folder is there. A "Container" is a folder/directory. Then check if you need to write the folder.
# This should allow your script to continue of error.
$ErrorActionPreference = "Continue"
# check if "C:\Temp\Foo" exist. if not make C:\Temp\foo"
$nfle = 'C:\Temp\foo'
[bool]$checkfle = Test-Path $nfle -PathType Container
if ( $checkfle -eq $True)
{
Write-Output "$nfle Exists"
}
else
{
New-Item -ItemType "Directory" -Path "C:\Temp\" -Name "foo"
}
# check if "C:\Temp\boo" exist. if not make C:\Temp\boo"
$BooFilePath = "C:\Temp\boo"
[bool]$checkboo = Test-Path $BooFilePath -PathType Container
if ( $checkboo -eq $True)
{
Write-Output " $BooFilePath Exists"
}
else
{
New-Item -ItemType "Directory" -Path "C:\Temp\" -Name "boo"
}
# This makes the folder C:\Temp\boo\foo.
# $cpypste = Copy-Item -Path "C:\Temp\foo\" -destination "C:\Temp\boo\"
# If you want copy the contents of foo into boo you will need * or -recurse
$cpypste = Copy-Item -Path "C:\Temp\foo\*" -destination "C:\Temp\boo\" -PassThru
Write-Host "Succesful Copy of Folders"
$cpypste.FullName
I have tried the demo provided and it works from my side, multiple times, so I was not able to re-create the problem.
If you would like to debug scripts in PowwerShell, you may follow this link:
https://learn.microsoft.com/en-us/powershell/scripting/components/ise/how-to-debug-scripts-in-windows-powershell-ise?view=powershell-6
I am not sure, why you are storing the result of Copy-Item into a variable, as it is null?
Hope it helps!
I would like to copy files between folders. Just modified (CSV files with new entries) in current day and one day before.
Here is my code:
foreach ($file in (Get-ChildItem "D:\Shares\WinCAP Data\DAYPROT\OFS-222_2")) {
if ($file.LastWriteTime = (Get-Date).AddDays(-1)) {
Copy-Item -Path "D:\Shares\WinCAP Data\DAYPROT\OFS-222_2\*.csv" -Destination "\\Oracle\MP"
"copying $file"
} else {
"not copying $file"
}
}
What is wrong - any suggestions?
You need to compare the date with -gt otherwise your're looking for files that were copied at that EXACT time.
Note that doing (Get-Date).AddDays(-1) is perfectly valid but will give you anything modified in the last 24 hours.
$DestinationFolder = "\\Oracle\MP\"
$EarliestModifiedTime = (Get-date).AddDays(-1)
$Files = Get-ChildItem "D:\Shares\WinCAP Data\DAYPROT\OFS-222_2\*.csv"
foreach ($File in $Files) {
if ($File.LastWriteTime -gt $EarliestModifiedTime)
{
Copy-Item $File -Destination $DestinationFolder
Write-Host "Copying $File"
}
else
{
Write-Host "Not copying $File"
}
}
If you didn't want to write out the "Copying ..." and "Not Copying ..." then you could simplify this quite a bit.
$DestingationFolder = "\\Oracle\MP\"
$EarliestModifiedTime = (Get-date).AddDays(-1)
Get-ChildItem -File |? { $_.LastWriteTime -gt $EarliestModifiedTime } | Copy-Item -Destination $DestingationFolder
Finally, if you want to copy anything since the beginning of (eg midnight at the start of) yesterday then change the following line:
$EarliestModifiedTime = (Get-date).AddDays(-1).Date
#Mr Tree I have one more related question.
I got few times per day new file at the location D:\Shares\WinCAP Data\DAYPROT\OFS-HT (location 1) with fixed name abcDD.MM.YYYY.csv (abc03.09.2015.csv) and I have a service which every 10 minutes call my powershell script below. I made as you suggest before in upper posts. My goal is: 1. to check if there is new file with name abcDD.MM.YYYY.csv | 2. rename it into abcDD.MM.YYYYHT.csv and move it to "\Oracle\MP\PURO\" (location 2) folder where I need to rewrite it with existing for current day.
Problem is that if the file already exists on the location 2, script does not want to move it and rewrite it? Thanks for hints.
$DestingationFolder = "\\Oracle\MP\PURO\"
$EarliestModifiedTime = (Get-date).AddDays(-1)
Get-ChildItem "D:\Shares\WinCAP Data\DAYPROT\OFS-HT\*.csv" | ?{!($_.fullname -match "HT\.csv")} | Rename-Item -NewName { $_.Name -replace "\.csv", "HT.csv" }
$Files = Get-ChildItem "D:\Shares\WinCAP Data\DAYPROT\OFS-HT\*.csv" -File
foreach ($File in $Files) {
if ($File.LastWriteTime -gt $EarliestModifiedTime)
{
Move-Item $File -Destination $DestingationFolder
Write-Host "Moving $File"
}
else
{
Write-Host "Not moving $File"
}
}
I don't understand this error message I'm receiving when I try to run my powershell script. The purpose is to copy a .bat file into the main win 7 startup folder on a series of machines.
And the script I am running.
$ServerList = Get-Content "C:\ServersList.txt" #Change this to location of servers list
$SourceFileLocation = "C:\firefox_issue.bat" #For example: D:\FoldertoCopy\ or D:\file.txt
$Destination = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" #Example: C$\temp
foreach ($_ in $ServerList)
{Copy-Item $SourceFileLocation -Destination \\$_\$Destination -Recurse -PassThru}
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Write-Host
Write-Host "A"
Write-Host "B"
Write-Host "C"
Because your location is getting set to:
\\SERVERNAME\C:\ProgramData...
and it should be:
\\SERVERNAME\C$\ProgamData...
Your destination needs to be:
$Destination = 'C$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup'
And your loop should be:
foreach($server in $serverList) {
Copy-Item $SourceFileLocation -Destination "\\$server\$Destination" -Recurse
}
You should probably avoid explicitly using $_ as a variable name as $_ is a special variable for accessing an object in the pipeline.
Did you read the comment behind the $Destination line?
This is a UNC path.
\\server1\c:\programdata\ is not a valid UNC-path. Try:
$Destination = "C$\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup"
Also, $_ is a reserved variable for pipeline input, so you need to change it, like:
foreach ($server in $ServerList)
{Copy-Item $SourceFileLocation -Destination \\$server\$Destination -Recurse -PassThru}