Create zip of folder and then delete the contents - powershell

I have a simple folder structure that I need to zip up to upload to AWS Lambda function
node-modules/
index.js
package.json
The files above are in the root directory. Basically the end goal is I would like a zip of all of these files and sub-files/directories instead of the structure as it is.
When I try to run the command below it says it can't access E://apps/myapp/release.zip because it's being used by another process. However I can see it starts to create release.zip but it does not have all the contents.
Add-Type -Assembly "System.IO.Compression.FileSystem";
[System.IO.Compression.ZipFile]::CreateFromDirectory(E://apps/myapp, E://apps/myapp/release.zip);
So I tried another approach. Take the folder and two files and copy them into a temporary folder, then try to zip it back into the root.
Copy-Item E://apps/myapp E://apps/myapp/temp -recurse
I do see a temp/ folder but within the temp folder it's like an inception of never ending copies until the file path gets too long.
Any tips would be much appreciated.

Issue could be that you are creating the zip file in the same folder that you are trying to compress. And you basically do the same thing when you tried using the temporary folder, hence the inception.
Try creating destination outside of the source folder being compressed.
$source = "E://apps/myapp"
$destination = "E://apps/myapp.release.zip"
# If the archive already exists, an IOException exception is thrown.
if(Test-Path $destination) {
Remove-Item -Path $destination -Force -Recurse -Confirm:$false
}
[Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )
[System.IO.Compression.ZipFile]::CreateFromDirectory($source, $destination)
# Once archive created delete folder
if(Test-Path $destination) {
Remove-Item -Path $source -Force -Recurse -Confirm:$false
Write-Host "directory removed: $source"
}

Related

PowerShell to move subitems of multiple folders into their own subfolders

I'm working on a project cleaning up a file server's folder redirection folders. Would like to ask for some help with a PS script that would move the files in user folders into new "Documents" sub-folders, as we're facing manually performing this for a lot of profiles.
A tree example currently looks like:
―FolderRedirection
―――JContoso
――――――File.docx
――――――File.pptx
―――MDerby
――――――File.docx
――――――File.pptx
I'd like to be able to achieve:
―FolderRedirection
―――JContoso
――――――Documents
―――――――――File.docx
―――――――――File.pptx
―――MDerby
――――――Documents
―――――――――File.docx
―――――――――File.pptx
This should work, bear in mind for future questions you should provide at least a minimal attempt at solving the problem.
The inline comments should help you with the code logic.
# get all folders in `FolderRedirection`
foreach($dir in Get-ChildItem .\FolderRedirection -Directory) {
# create a new `Documents` folder in each sub folder
$dest = $dir | Join-Path -ChildPath Documents
$dest = New-Item $dest -ItemType Directory -Force
# get all files in each folder and move them to the new folder
$dir | Get-ChildItem -File | Move-Item -Destination $dest
}

Copying files to directory whilst retaining directory structure from list

Good afternoon all,
I'm guessing this is super easy but really annoying for me; I have a text file with a list of files, in the same folders there are LOTS of other files but I only need specific ones.
$Filelocs = get-content "C:\Users\me\Desktop\tomove\Code\locations.txt"
Foreach ($Loc in $Filelocs){xcopy.exe $loc C:\Redacted\output /s }
I figured this would go through the list which is like
"C:\redacted\Policies\IT\Retracted Documents\Policy_Control0.docx"
and then move and create the folder structure in a new place and then copy the file, it doesn't.
Any help would be appreciated.
Thanks
RGE
xcopy can't know the folder structure when you explicitly pass source file path instead of a source directory. In a path like C:\foo\bar\baz.txt the base directory could be any of C:\, C:\foo\ or C:\foo\bar\.
When working with a path list, you have to build the destination directory structure yourself. Resolve paths from text file to relative paths, join with destination directory, create parent directory of file and finally use PowerShell's own Copy-Item command to copy the file.
$Filelocs = Get-Content 'locations.txt'
# Base directory common to all paths specified in "locations.txt"
$CommonInputDir = 'C:\redacted\Policies'
# Where files shall be copied to
$Destination = 'C:\Redacted\output'
# Temporarily change current directory -> base directory for Resolve-Path -Relative
Push-Location $CommonInputDir
Foreach ($Loc in $Filelocs) {
# Resolve input path relative to $CommonInputDir (current directory)
$RelativePath = Resolve-Path $Loc -Relative
# Resolve full target file path and directory
$TargetPath = Join-Path $Destination $RelativePath
$TargetDir = Split-Path $TargetPath -Parent
# Create target dir if not already exists (-Force) because Copy-Item fails
# if directory does not exist.
$null = New-Item $TargetDir -ItemType Directory -Force
# Well, copy the file
Copy-Item -Path $loc -Destination $TargetPath
}
# Restore current directory that has been changed by Push-Location
Pop-Location
Possible improvements, left as an exercise:
Automatically determine common base directory of files specified in "locations.txt". Not trivial but not too difficult.
Make the code exception-safe. Wrap everything between Push-Location and Pop-Location in a try{} block and move Pop-Location into the finally{} block so the current directory will be restored even when a script-terminating error occurs. See about_Try Catch_Finally.

Need assistance copying task

I have .dll and .sys files under folder xyz
xyz
'QcXhciFilter8086\QcXhciFilter8086.sys'
'qSarMgr8086\qSarMgr.dll'
'qcwlan_wpextwapi8086\WapiIhvExt.dll'
These need to be copied something like this under new folder
new
'QcXhciFilter8086\QcXhciFilter8086.sys'
'qSarMgr8086\qSarMgr.dll'
'qcwlan_wpextwapi8086\WapiIhvExt.dll'
What i have tried:
'Copy-Item -Path $file_path\..\*sys -Destination C:\Users\Path\new\'
Here '$file_path = \xyz\QcXhciFilter8086\QcXhciFilter8086.sys'
Result: Only .sys.dll files getting copied directly under "new" folder. However i want them under the driver name. Something like this 'new\QcXhciFilter8086\QcXhciFilter8086.sys'
Okay, I think I understand what you are asking for...
You have a folder structure like this:
[xyz]
QcXhciFilter8086
QcXhciFilter8086.sys
qSarMgr8086
qSarMgr.dll
qcwlan_wpextwapi8086
WapiIhvExt.dll
And you want this copying to another folder. Using this will copy the folder structure and files from the xyz folder to the new folder. This will copy everything, however. If you only want to copy the files that are only .sys and .dll then you will need to add another Get-ChildItem in the existing ForeEach-Object loop to look at the current directory.
Here is my proposed solution:
$source = "c:\path\to\xyz"
$destination = "c:\path\to\new"
Get-ChildItem -Path $source -Directory | ForEach-Object{
Copy-Item $_.FullName -Destination $destination -Recurse -Container
}

Powershell - Comparing and overriding a folder

I am trying to create a powershell script to compare 1 folder to another, say Folder A to Folder B. I want my script to make folder B look exactly like Folder A every time this script runs. Overriding anything in there, and deleting anything in Folder B that is not in Folder A. I have no code for it yet, and everything ive tried does not work. I made a script that copies from Folder A to Folder B and it works but wont delete anything different and wont override a file. So if its already in there, it doesn't care that the item in Folder A is newer, it will keep Folder B old file:
Test-Path "C:\Users\Shawn\Desktop\Scripts\New Folder"
if((Test-Path True))
{
Copy-Item -Path "C:\Users\Shawn\Pictures\" -Destination "C:\Users\Shawn\Desktop\Scripts\New Folder" -recurse
}
else
{
New-Item -Path "C:\Users\Shawn\Desktop\Scripts\New Folder" -ItemType directory
Copy-Item -Path "C:\Users\Shawn\Pictures\" -Destination "C:\Users\Shawn\Desktop\Scripts\New Folder" -recurse
}

Should Copy-Item create the destination directory structure?

I'm trying to copy a file to a new location, maintaining directory structure.
$source = "c:\some\path\to\a\file.txt"
destination = "c:\a\more\different\path\to\the\file.txt"
Copy-Item $source $destination -Force -Recurse
But I get a DirectoryNotFoundException:
Copy-Item : Could not find a part of the path 'c:\a\more\different\path\to\the\file.txt'
The -recurse option only creates a destination folder structure if the source is a directory. When the source is a file, Copy-Item expects the destination to be a file or directory that already exists. Here are a couple ways you can work around that.
Option 1: Copy directories instead of files
$source = "c:\some\path\to\a\dir"; $destination = "c:\a\different\dir"
# No -force is required here, -recurse alone will do
Copy-Item $source $destination -Recurse
Option 2: 'Touch' the file first and then overwrite it
$source = "c:\some\path\to\a\file.txt"; $destination = "c:\a\different\file.txt"
# Create the folder structure and empty destination file, similar to
# the Unix 'touch' command
New-Item -ItemType File -Path $destination -Force
Copy-Item $source $destination -Force
Alternatively, with PS3.0 onwards, you can simply use the New-Item to create the target folder directly, without having to create a "dummy" file, e.g. ...
New-Item -Type dir \\target\1\2\3\4\5
...will happily create the \\target\1\2\3\4\5 structure irrespective of how much of it already exists.
Here's a oneliner to do this. Split-Path retrieves the parent folder, New-Item creates it and then Copy-Item copies the file. Please note that the destination file will have the same filename as the source file. Also, this won't work if you need to copy multiple files to the same folder as with the second file you'll get An item with the specified name <destination direcory name> already exists error.
Copy-Item $source -Destination (New-Item -Path (Split-Path -Path $destination) -Type Directory)
I had files in a single folder in Windows 7 that I wanted to rename and copy to nonexistent folders.
I used the following PowerShell script, which defines a Copy-New-Item function as a wrapper for the Test-Item, New-Item, and Copy-Item cmdlets:
function Copy-New-Item {
$SourceFilePath = $args[0]
$DestinationFilePath = $args[1]
If (-not (Test-Path $DestinationFilePath)) {
New-Item -ItemType File -Path $DestinationFilePath -Force
}
Copy-Item -Path $SourceFilePath -Destination $DestinationFilePath
}
Copy-New-Item schema_mml3_mathml3_rnc schema\mml3\mathml3.rnc
# More of the same...
Copy-New-Item schema_svg11_svg_animation_rnc schema\svg11\svg-animation.rnc
# More of the same...
Copy-New-Item schema_html5_assertions_sch schema\html5\assertions.sch
# More of the same...
(Note that, in this case, the source file names have no file extension.)
If the destination file path does not exist, the function creates an empty file in that path, forcing the creation of any nonexistent directories in the file path. (If Copy-Item can do all that by itself, I could not see how to do it from the documentation.)
It is coming late, but as I stumbled upon this question looking for a solution to a similar problem, the cleanest one I found elsewhere is using robocopy instead of Copy-Item. I needed to copy the whole file structure together with the files, that's easily achieved via
robocopy "sourcefolder" "destinationfolder" "file.txt" /s
Detail about robocopy: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy
None of the current answers worked for me to fix the Could not find a part of the path error raised by Copy-Item. After some research and testing, I discovered this error can be raised if the Destination path goes over the 260 character Windows path length limit.
What I mean by that is: if you supply a path to the Destination argument of Copy-Item and any of the files you are copying would exceed the 260 character limit when copied to the Destination folder, Copy-Item will raise the Could not find a part of the path error.
The fix is to shorten your Destination path, or to shorten/flatten the folder structure in the source directory that you are trying to copy.
May be Helpfull:
$source = 'c:\some\path\to\a\file.txt'
$dest = 'c:\a\more\different\path\to\the\file.txt'
$dest_dir = 'c:\a\more\different\path\to\the\'
[System.IO.Directory]::CreateDirectory($dest_dir);
if(-not [System.IO.File]::Exists($dest))
{
[System.IO.File]::Copy($source,$dest);
}
I have been digging around and found a lot of solutions to this issue, all being some alteration not just a straight copy-item command. Grant it some of these questions predate PS 3.0 so the answers are not wrong but using powershell 3.0 I was finally able to accomplish this using the -Container switch for copy-item.
Copy-Item $from $to -Recurse -Container
this was the test i ran, no errors and destination folder represented the same folder structure.
New-Item -ItemType dir -Name test_copy
New-Item -ItemType dir -Name test_copy\folder1
New-Item -ItemType file -Name test_copy\folder1\test.txt
#NOTE: with no \ at the end of the destination the file is created in the root of the destination, does not create the folder1 container
#Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2 -Recurse -Container
#if the destination does not exists this created the matching folder structure and file with no errors
Copy-Item D:\tmp\test_copy\* D:\tmp\test_copy2\ -Recurse -Container