storing filename and path in variable to use with Copy-Item - powershell

I'm trying to write a script to find the most recent .bak in a certain directory and copy the file to another location. When I use Get-ChildItem the file name isn't enlcosed in single quotes so when i try to copy it Copy-Item cant find it. ( I think)
$dir = 'E:\Backups\'
$dest = 'F:\'
$filename = Get-ChildItem -path $dir -filter *.bak | Sort-Object CreationTime -Descending | Select-Object -First 1 | select FullName | Format-Table -HideTableHeaders
echo #filename
copy-Item -path #filename -destination #dest
echo #filename returns E:\Backups\company.bak but i think need 'E:\Backups\company.bak' for it to work?
PS C:\Users\prodadmin> copy-Item -path #filename -destination #dest
Copy-Item : A positional parameter cannot be found that accepts argument 'Microsoft.PowerShell.Commands.Internal.Format.GroupStartData'.
At line:1 char:1
+ copy-Item -path #filename -destination #dest
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Copy-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
As above, typed it all in one go.

Get-ChildItem returns FileInfo (and also DirectoryInfo) objects.
By using select FullName you tell PowerShell to return an new object with one property called FullName and you lose the Name property.
Format-Table is a cmdlet used for display purposes only, so never use that on data you want to process further.
Lastly, you prefix the variables you have with # instead of $
Try
$dir = 'E:\Backups\'
$dest = 'F:\'
$file = Get-ChildItem -Path $dir -Filter '*.bak' -File | # do not return directories
Sort-Object CreationTime -Descending | # or did you mean LastWriteTime (=> last modified date) ?
Select-Object -First 1 # return just 1 FileInfo object
Write-Host "Found $($file.Name)" # write to console
Copy-Item -Path $file.FullName -Destination $dest

Related

Include folder name in file name as part of a loop

I try to get the directory name as part of a filename. The problem is that I want to do this for each file in a different separate folder, which does not seem to work.
What I have come to thus far is that I am able to get a list of subfolders ($GetAllActionTargetSubFolders) that each contain one or more files. In each of the subfolders, the files are combined into one file with the name 'temp'. Now, what does not work is, I want to rename this combined 'temp' file that is in each of the subfolders and want to include the subfolder name as such: FoldernameA_Consolidated202209161304.rpt (instead of temp.rpt)
I thought that the '$_.Directory.Name' would give me the directory name, but then I get this error message:
Rename-Item : Could not find a part of the path.
At line:5 char:125
+ ... de *temp* | Rename-Item -NewName {$_.Directory.Name + "_Consolidated ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (\\networkdrive\R...ctions\temp.rpt:String) [Rename-Item], DirectoryNotFoundException
+ FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
This is the script that I have thus far:
#get a list of all sub directories:
$ActionTargetFolder = "\\networkdrive\2_ActionData_Prep\"
$GetAllActionTargetSubFolders = Get-ChildItem -Path $ActionTargetFolder -Recurse | Where-Object { $_.PSIsContainer -eq $true}
#for each sub directory, make 1 file that contains all lines from the files that are in that specific sub directory:
ForEach ($foldername in $GetAllActionTargetSubFolders.FullName) {Get-ChildItem $foldername -Recurse -File -Include *.rpt | get-content | sort | get-unique | Out-File -FilePath "$($foldername)\temp.rpt"-Force }
#rename the 'temp' file that is created and include the sub-directory name, text and date/time:
ForEach ($foldername in $GetAllActionTargetSubFolders.FullName) {Get-ChildItem $foldername -Recurse -File -Include *temp* | Rename-Item -NewName {$_.Directory.Name + "_Consolidated" + $((Get-Date).ToString('yyyyMMddhhmm')) + ".rpt"}}
I hope someone could help me with this
As Cid already commented, there is no need to create a file with name temp.rpt first and rename it afterwards.
By naming the file as you want it straight away, you don't need that second loop.
Also, when using Get-ChildItem and want it to filter for just one extension, you should use -Filter instead of -Include because this works a lot faster.
Try:
# get a list of all sub directories:
$ActionTargetFolder = "\\networkdrive\2_ActionData_Prep\"
$GetAllActionTargetSubFolders = Get-ChildItem -Path $ActionTargetFolder -Directory -Recurse
# for each sub directory, make 1 file that contains all lines from the files that are in that specific sub directory:
foreach ($folder in $GetAllActionTargetSubFolders) {
# create the full path and filename for the output
$outFile = Join-Path -Path $folder.FullName -ChildPath ('{0}_Consolidated_{1:yyyyMMddHHmm}.rpt' -f $folder.Name, (Get-Date))
$content = $folder | Get-ChildItem -File -Filter '*.rpt' | Get-Content
$content | Sort-Object -Unique | Set-Content -Path $outFile
}

Unable to work with lines i csv created by export-csv

After running this script:
# Input path
$input_path = 'C:\Users\larry\Pictures\2003'
# Export file
$documents_export_file = 'C:\Users\larry\Documents\Temp\ffmpeg\fullnames.csv'
# Copy-to folder
$copy_to = "C:\Users\larry\Documents\Temp\ffmpeg\movies"
# List filenames in $documents_export_file
Get-ChildItem -Attributes !Directory -Path $input_path -Recurse -force | select-object -Property fullName | Export-Csv $documents_export_file
# Copy the files listed in $documents_export_file to $copy_to folder
get-content $documents_export_file | Foreach-Object { copy-item -Path $_ -Destination $copy_to}
I get the following error:
copy-item : Cannot find drive. A drive with the name '"C' does not exist.
At line:18 char:55
+ ... ort_file | Foreach-Object { copy-item -Path $_ -Destination $copy_to}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: ("C:String) [Copy-Item], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
copy-item : Cannot find drive. A drive with the name '"C' does not exist.
At line:18 char:55
+ ... ort_file | Foreach-Object { copy-item -Path $_ -Destination $copy_to}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: ("C:String) [Copy-Item], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
As far as I can figure out, it has something to do with my Export-Csv, bur I can´t figure it out.
Please give me a hand.
There's no need to export the list of files to CSV in the first place - assign the output from Get-ChildItem to a variable instead, and then pipe the contents directly to Copy-Item:
$files = Get-ChildItem -Attributes !Directory -Path $input_path -Recurse -Force
$files |Copy-Item -Destination $copy_to

Search directory for unique path and patterns

I am trying to search a directory structure, and files for all instances of where a pattern exists. Than I want that file location recorded in a log file that I can review latter. I looked at various posts, but I have not found a similar example where this is happening. Reviewed posts include:
PowerShell Scripting - Get-ChildItem
Search List for unique pattern
Search directory and sub-directories for pattern in a file
Use an Easy PowerShell Command to Search Files for Information
Get full path of the files in PowerShell
Here is the code I am using to recuse through the folder structure:
#Set variables for paths
$Results = "C:\Results"
$Source = "C:\Test\*"
$Destination = "C:\MyTest\"
#Create file name for each report with date and time of run
$ReportDate = (Get-Date).ToString("dd-MM-yyyy-hh-mm-ss")
$CustomPattern = Read-Host 'What pattern are you looing for?'
$CustomPatternLog = New-Item -itemType File -Path C:\Results -Name $("CustomerPattern_" + $ReportDate + ".txt")
$CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | Select-String -pattern $CustomPattern | Select-Object -Unique Path) {$file.path}
$CustomPattern > "$($Results)\$($CustomPatternLog)"
However, this code is returning the following error:
Get-ChildItem : The specified path, file name, or both are too long.
The fully qualified file name must be less than 260 characters, and
the directory name must be less than 248 characters. At line:19
char:36
+ $CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (C:\Test\Mor...ofiles\Customer:St ring) [Get-ChildItem],
PathTooLongException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChil dItemCommand
Do you have a better way to do the same operation?
replace this
$CustomPatternLog = New-Item -itemType File -Path C:\Results -Name $("CustomerPattern_" + $ReportDate + ".txt")
$CustomPattern = foreach ($file in Get-ChildItem -Path $Destination -Recurse | Select-String -pattern $CustomPattern | Select-Object -Unique Path) {$file.path}
$CustomPattern > "$($Results)\$($CustomPatternLog)"
with this
$files = Get-ChildItem -Path $Destination -Recurse
#in case you would need the path replace FullName with PsParentPath
$result = ($files | ?{$_.name -like "*$CustomPattern*"}).FullName
$result | out-file ($CustomPattern + "_" + $ReportDate + ".txt")
and since its shell you can do the same with one liner
(Get-ChildItem -Path $Destination -Recurse | ?{$_.name -like "*$CustomPattern*"}).FullName | out-file ($CustomPattern + "_" + $ReportDate + ".txt")

Powershell getting full path information

I have a directory called Videos. Inside this directory, are a bunch of sub directories of various cameras. I have a script that will check each of the various cameras, and delete recordings older than a certain date.
I am having a bit of trouble getting the full directory information for the cameras. I am using the following to get it:
#Get all of the paths for each camera
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object FullName
And then I loop through each path in $paths and delete whatever I need to:
foreach ($pa in $paths) {
# Delete files older than the $limit.
$file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
$file | Remove-Item -Recurse -Force
$file | Select -Expand FullName | Out-File $logFile -append
}
When I run the script, I am getting errors such as:
#{FullName=C:\Videos\PC1-CAM1}
Get-ChildItem : Cannot find drive. A drive with the name '#{FullName=C' does not exist.
At C:\scripts\BodyCamDelete.ps1:34 char:13
+ $file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsCont ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{FullName=C:String) [Get-ChildItem], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way to strip that #{FullName= off of the Path? I think that may be what the issue is.
In your case $pa is an object with a FullName property. The way you would access that would be this.
$file = Get-ChildItem -Path $pa.FullName -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
However it would just be simpler to change only this line and leave
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
-ExpandProperty will just return the string instead of the object that Select-Object was returning.
You are nearly there. What you want is the -ExpandProperty argument for Select-Object. This will return the value of that property, instead of a FileInfo object with one property, that property being FullName. This should resolve it for you:
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
Edit: Looks like Matt beat me to it by a minute.

Powershell - Export Multiple CSV's into unique folders

I have been working on a PowerShell script for the better part of well a week or two. I've been able to get some parts of it working however I'm unable to fully get this automated.
I deal with a lot of CSV files on a daily basis, I have been tasked with uploading them into our software however sometimes they're too large to handle so I break them down based upon their "type" (it's a column in the CSV) and I export it to a single CSV per "type". I've been able to accomplish this with the following:
$file = gci -Filter "*.csv";
Import-Csv $file `
| Group-Object –Property “type” `
| Foreach-Object `
{
$path=$_.name+”.csv” ; $_.group `
| Export-Csv –Path $path –NoTypeInformation
}
So this works wonderfully, for each individual CSV. Unfortunately I don't have the time to do this for each individual CSV. Now I come to my other PowerShell script:
get-childitem -Filter "*.csv" `
| select-object basename `
| foreach-object{ $path=$_.basename+".csv" #iterate through files.
if(!(Test-Path -path $_.basename)) #If the folder of the file can't be found then it will attempt to create it.
{
New-Item $_.basename -type directory; $file=$_.basename+".csv";
Import-Csv $file `
| Group-Object -Property "Type" `
| Foreach-Object {
$path=$_.name+".csv"; $_.group `
| `
if(!(Test-Path -path $path2))
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
else
{
"Failed on: " + $_.basename
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
}
}
}
else
{
Import-Csv $path `
| Group-Object -Property "Type" `
| Foreach-Object {$path=$_.basename+".csv" ; $_.group
if(Test-Path -path $._)
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
#else
#{
Write-Host "Failed on: $_.basename"
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
#}
}
}
}
I just can't wrap my head around "why" this isn't working effectively. I have two conditionals. Is there a folder for the CSV? If no create one. I have to have another one because one of the "types" contains a \ which errors out if I don't have the folder, so I automatically try to create it. When I run the script I get the Path is null.
The Error is:
The term ' ' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
At C:\Users\c.burkinshaw\foldermake.ps1:11 char:26
+ | ` <<<<
+ CategoryInfo : ObjectNotFound: ( :String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Test-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
Any help would be greatly appreciated, if you have questions please don't hesitate to ask.
You have not defined $path2 anywhere, so something like test-path -path $path2 will say path is null. And in one place you are using $._ which will again give errors.
Edit after question updated with error message:
Your error message also says the same
Test-Path : Cannot bind argument to parameter 'Path' because it is
null. At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
Also the other error is in:
$path=$_.name+".csv"; $_.group `
| `
what are you trying to do here with the $_.group?
It is not proper. You cannot do $_.group | and provide some if statement.
Other comments:
Why are using $_.basename and then appending .csv? You could have just used $_.name. Try to not use the select-object basename - I don't see the value.
Extract the common import-csv and export-csv part into a function.