Test a Path and a File (Nested IFs) - powershell

Long day, might be missing something obvious, but the nested IF statements below should work. Any suggestions?
Basically, what I am trying to do:
Take a given hostname (this will later on be incorporated into a loop).
Take a log file and move it from one location to another (location is always constant).
2A. Test IF the folder exists:
2A-1. If the folder exists, test if the file is in the folder.
2A-1a. True: Delete the file
2A-1b. False: Copy the file to the folder.
2A-2. Else: Copy the file to the folder.
2B. ELSE:
2B-1. Create the folder.
2B-2. Copy the file to the folder
I did the below:
$Computer = "hostName"
Enter-PSSession -ComputerName $($Computer)
$LogFileName = "program_" + $Computer + ".log"
$LogFilePath = "\\$Computer\C$\users\$env:USERNAME\desktop\$LogFileName"
$DestPath = "\\$Computer\C$\users\$env:USERNAME\ProgramTest\"
$LogCopy = "programCopy_" + $Computer + ".log"
IF(Test-Path $($DestPath)){
If(Test-Path "$DestPath\$LogCopy"){
Remove-Item "$DestPath\$LogCopy"
Copy-Item $($LogFilePath) $($DestPath)
}
Else{
Copy-Item $($LogFilePath) $($DestPath)
}
ELSE{
New-Item -ItemType directory -Path $($DestPath)
Copy-Item $($LogFilePath) $($DestPath)
}
}

I see you have already accepted an answer but I wanted to offer and improvement on the logic. The nested if's, while do work, have some redundancies in them. Assuming I understand your intention...
# If the folder does not exist create it. If it does move on
If(!(Test-Path $DestPath)){New-Item -ItemType directory -Path $DestPath}
# If the log file already exists. Remove It.
If(Test-Path "$DestPath\$LogCopy"){Remove-Item "$DestPath\$LogCopy"}
# Regardless of what happens we are going to copy the file. No need to repeat the code.
Copy-Item $($LogFilePath) $($DestPath)
While that is an improvement on the logic we can take this a little further. If you want to be sure the file is fresh and overwritten Copy-Item will handle that for you.
# If the folder does not exist create it. If it does move on
If(!(Test-Path $DestPath)){New-Item -ItemType directory -Path $DestPath}
# Regardless of what happens we are going to copy the file. No need to repeat the code.
Copy-Item $LogFilePath $DestPath -Confirm:$false -Force
$() is the notation for a subexpression. A common use in similar context would be to ensure that a variable expands properly in a string. As shown in the following example
PS C:\Users\Cameron> $data = #{Matt="Awesome"}
PS C:\Users\Cameron> "$data.Matt"
System.Collections.Hashtable.Matt
PS C:\Users\Cameron> "$($data.Matt)"
Awesome
Currently in your code, while causing no harm, it is redundant.

Beyond the dubious use of $($Variable) (completely redundant; just use $Variable), you've misplaced a closing brace. The last five lines should look like this:
}
ELSE{
New-Item -ItemType directory -Path $($DestPath)
Copy-Item $($LogFilePath) $($DestPath)
}
If that doesn't work, let us know what's actually happening: errors and such when you try to run it.

Related

Powershell building broken paths

I have a script being run via scheduled task. Occasionally when the script runs it outputs a broken path. The path should be a folder, named with the current date, however sometimes this path is not a folder but instead a file, type '28 File'. I have attached an image of the broken path below.
The script will only build this path if it does not exist, per the Test-Path shown below. I can only replicate the error if a user deletes the $dailyLocal folder, when the next pass of the script tries to rebuild the path, we see the broken path.
Are there any additional parameters I can put in place to prevent this? Does anyone even understand the error or what '28 File' is?
EDIT: The 28 is from the date format, Powershell thinks I am asking to build a file with extension .28, I have already specified the new path should be a folder. Are there any other measures I can take to specify this as a folder?
#name variables
$bay = 'X1'
$hotFolder = 'C:\Hot_Folder'
$uploadArchive = 'C:\Hot_Folder\Archive'
$today = get-date -Format yyyy.MM.dd
$dailyServer = "\\server\$today $bay"
$dailyLocal = "$uploadArchive\$today $bay"
#build local archive and server archive path for date and bay (test if exists first)
if(!((Test-Path -Path $dailyServer -PathType Container) -or (Test-Path -Path $dailyLocal -PathType Container))){
New-Item -ItemType directory -Path $dailyServer, $dailyLocal
}
#copy to server archive, then move to local archive
$uploadImages = GCI $hotFolder -Filter *.jpg
foreach ($image in $uploadImages){
Write-Host "this is the new valid image" $image -ForegroundColor Green
Copy-Item $image.FullName -Destination $dailyServer -Force
Move-Item $image.FullName -Destination $dailyLocal -Force
}

PowerShell script isn't copying like I want

Right in the beginning I should note that I am a bloody beginner because I can't attend it classes in my grade.
I want to create a PowerShell script which will copy everything from
C:\Users\Robert\Desktop\test(lots of folders)
to
C:\Users\Robert\Desktop\neu(lots of folders with the exact same names as above)\price
As an absolute beginner I thought that it will be ok to replace the variable folder name with $_Name because it is the same name in both but I am obviously wrong and don't know why.
Here is my attempt
Copy-Item "C:\Users\Robert\Desktop\test\$_name\*" -Destination "C:\Users\Robert\Desktop\neu\$_Name\price" -Recurse
It is copying something but in one package in a new folder in "neu".
I can't avoid creating this script because it would take me at least two or three days to do it by hand.
I am also sorry for my poor English skills
Thank you
the $_ represents the current pipeline item. i don't see a pipeline in there ... [grin]
the following works by grabbing every file in the source dir & its subdirs, and copying that structure to the destination dir. it uses Splatting to structure the parameters neatly.
$SourceDir = "$env:TEMP\Apps - Copy"
$DestDir = "$env:TEMP\Apps - Copy - Two"
$CI_Params = #{
LiteralPath = $SourceDir
Destination = $DestDir
Force = $True
Recurse = $True
}
Copy-Item #CI_Params
If my understanding is correct:
$src = 'C:\Users\Robert\Desktop\test'
$dst = 'C:\Users\Robert\Desktop\neu\{0}\price'
Get-ChildItem $src -Directory | ForEach-Object {
Copy-Item -Path "$($_.FullName)\*" -Destination ($dst -f $_.BaseName) -Recurse -Force -WhatIf
}
Remove -WhatIf to actually do it.

Check if file exists, then move it

I'm trying to write a few lines of code in powershell, to check if a file arrived to a specific folder. If the file is there, copy it to another folder. No action required if the file is not there. So far I have only the copying part:
cd C:\
Move /y "C:\myfolder\*.csv" "C:\MyDestinationFolder"
I can't find a simple code to check if the file is present.
Maybe you can use this:
$SourceFile = "C:\source\file.txt"
$Destination = "C:\destination\"
if(Test-Path -Path $SourceFile)
{
Copy-Item -Path $SourceFile -Destination $Destination
}
try this :
move-Item "C:\myfolder\*.csv" "C:\MyDestinationFolder" -Force -ErrorAction SilentlyContinue

Why is PowerShell copying to a random location?

I have the following simple script:
$workingDir = "C:\foo\bar"
$projectsDir = "C:\foo"
Copy-Item -Path "$projectsDir\some subpath\MyFile1.dll" -Destination $workingDir
Copy-Item -Path "$projectsDir\somewhere else\MyFile2.dll" -Destination $workingDir
Copy-Item -Path "$projectsDir\another place\MyFile3.dll" -Destination $workingDir
For some unknown reason, every time I run this script it copies the files to the correct location ($workingDir) and also copies them to $projectsDir\some subpath\something\else. I have to go delete the extra files from the other location every time this script is run.
So far I've tried:
changing variable names
specifying -Destination "$workingDir\MyFile1.dll"
using $null = Copy-Item -Path "...."
I even tried replacing Copy-Item with xcopy.exe
and nothing changes. I put a breakpoint on the first Copy-Item command and looked at the variables - they all looked right. What's going on here?
The only other thing I could think of is to run the copy-item like this:
Copy-Item -Path $($projectsDir + "\some subpath\MyFile1.dll") -Destination $workingDir
This is how I declare almost all of my Variable + SomethingElse scenarios. Since I haven't scene this behavior, I'll go back and test it some more to see what I can find. If I come up with something else, I redo my answer.
I rebooted my computer. Problem solved.

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