$folder = filestructure
# Get a recursive list of all folders beneath the folder supplied by the operator
$AllFolders = Get-ChildItem -Recurse -Path $Folder |? {$_.psIsContainer -eq $True}
# Get a list of all files that exist directly at the root of the folder
# supplied by the operator
$FilesInRoot = Get-ChildItem -Path $Folder | ? {$_.psIsContainer -eq $False}
Foreach ($File in ($FilesInRoot))
{
#Notify the operator that the file is being uploaded to a specific location
if($Global:successfullymigrated -contains $File){
Write-Host $File
}
}
###this part doesn't work
foreach($CurrentFolder in $AllFolders)
{
# Set the FolderRelativePath by removing the path of the folder supplied
# by the operator from the fullname of the folder
$FolderRelativePath = ($CurrentFolder.FullName).Substring($Folder.Length)
$FileSource = $Folder + $FolderRelativePath
$FilesInFolder = Get-ChildItem -Path $FileSource | ? {$_.psIsContainer -eq $False}
# For each file in the source folder being evaluated, call the UploadFile
# function to upload the file to the appropriate location
Foreach ($File in ($FilesInFolder))
{
Write-Host $File
if($Global:successfullymigrated -contains $File){
Write-Host $File
}
}
}
My code above is supposed to go through a file structure and checks to see if any of the file names are in the array (which is an array of strings with file names in them). My code works for the root files, prints out all the files that are in the array but when we get to checking the files in the other folders beyond the root it doesn't work. Even though it outputs the files that are in the file structure. I am completely stuck.
Forgive me if I have misunderstood but I read this
My code above is supposed to go through a file structure and checks to see if any of the file names are in the array
And interpreted that as you are just looking for file paths for files that match exactly a list of names you provide.
So I have this sample which should do just that.
$Global:successfullymigrated = #("template.txt","winmail.dat")
$folder = "C:\temp"
Get-ChildItem $folder -recurse | Where-Object{$Global:successfullymigrated -contains $_.Name -and !$_.psIsContainer} | Select-Object -ExpandProperty FullName
You should be able to incorporate this into your own code. It outputs the full paths to the matching files. The example I have outputs file from root and substructure.
C:\temp\winmail.dat
C:\temp\docs\template.txt
!$_.psIsContainer is to ensure that we do not get folders returned in our results. If you have PowerShell 3.0 or above then that can be replaced by the -File switch of Get-ChildItem
Related
I have a specific usecase where I need to identify if files from a list exist, and if so, copy them to a separate location with the relevant file structure kept. I need to keep my list of targets in the same script.
I believe my issue is something to do with the way the data inside isn't being parsed correctly due to ":" for drive letters, but I'm unsure of how to get round this issue.
As you can see from the code below, I attempted to fix the issue by ignoring the drive letter, and appending it during the Copy-Item, but it doesn't seem to work either. (e.g: C:\folder\file becomes \folder\file in the list.)
I created test directory to just help show the issue, of examples of files/folders that I want to grab (purely for testing, the real files are multiple locations/file types).
- test_dir_cmd
- folder
- folder1
* file2.db
* file3.json
* file2.txt
* file3.js
- folder2
* file.bak
* file.db
* file.txt
* temp.dat
This method works for folders and their contents, but not for specific files or wildcard.
"\USERS\$USER\AppData\Local\test_dir_cmd\folder\folder1",
"\USERS\$USER\AppData\Local\test_dir_cmd\folder\*.txt",
"\USERS\$USER\AppData\Local\test_dir_cmd\*\file.db",
"\USERS\$USER\AppData\Local\test_dir_cmd\temp.dat”
This is an example of how the list of files I'll need to get is presented and I'll need to work with.
Errors given:
Copy-Item : Illegal characters in path.
At F:\P2P.ps1:37 char:1
+ Copy-Item "C:$path" -Destination "$triage_location\$path" -Force -Rec ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Copy-Item], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.CopyItem
Command
Full script used for context:
$triage_location = "C:\temp\output\Triage\c"
ForEach-Object { #Looping through C:\Users to find folders that begin with numbers only and add to an array called $users
$users = #(Get-ChildItem -Path 'C:\Users'| Where-Object { $_.Name -match '^c+' } | Select -ExpandProperty Name)
}
Write-Host "users = $users"
write-host ""
$path_array = foreach ($user in $users) { # Loop through contents of users array and add each user to known locations
#(
"\USERS\$USER\AppData\Local\test_dir_cmd\folder\folder1",
"\USERS\$USER\AppData\Local\test_dir_cmd\folder\*.txt",
"\USERS\$USER\AppData\Local\test_dir_cmd\*\file.db",
"\USERS\$USER\AppData\Local\test_dir_cmd\temp.dat”
)
}
Write-Host "path_array = $path_array"
write-host ""
foreach ($path in $path_array) {
$a = Test-Path -Path "C:$path" # Creating variable called 'a' and setting it to Test-path value which is either True/False
if ($a -eq "True") # Test if browser location paths exist or not. If a returns True/False...
{
Write-Host "C:$path exists"
if(!(Test-Path -Path "$triage_location"))
{
New-Item -ItemType Directory -Path $triage_location
}
Copy-Item "C:$path" -Destination "$triage_location\$path" -Force -Recurse
}
else
{Write-Host "C:$path doesn't exist"}
}
if(Test-Path -Path "C:\temp\output\Triage")
{
Write-Host ""
Write-Host "Creating relevant .ZIP"
Compress-Archive -Path 'C:\temp\output\Triage' -DestinationPath 'C:\temp\output\P2P.zip' -Force # put zip in documents
}
Any help and advice on how I can fix this would be greatly appreciated!
The issue is that you are not joining the paths well. You do this:
-Destination "$triage_location\$path"
At that point $triage_location is C:\temp\output\Triage\c and $path is something like \USERS\TMTech\AppData\Local\test_dir_cmd\folder\folder1. You just make the path with string expansion but since $path starts with a \ and you include that in your string, so your string comes out looking like this:
"C:\temp\output\Triage\c\\USERS\TMTech\AppData\Local\test_dir_cmd\folder\folder1"
Use Join-Path instead:
Copy-Item (Join-Path 'C:\' $path) -Destination (Join-Path $triage_location $path) -Force -Recurse
I'm trying to write a script in PowerShell which reads in a "foreach" loop all the only files in a specific folder which contains "example" in it's name.
The problem is that I'm trying to save the content of each file in a variable without any success. Tried to use Get-Content $file and it throws the following error "Get-Content : Cannot find path" even though the path was set at the beginning to the Folder var and file actually contains the file that I need. I can't assign it to $FileContent
$Folder = Get-ChildItem U:\...\Source
foreach($file in $Folder)
{
if($file.Name -Match "example")
{
$FileContent = Get-Content $file
}
}
This happens as the FileInfo object's default behavior returns just the file's name. That is, there is no path information, so Get-Content tries to access the file from current directory.
Use FileInfo's FullName property to use absolute path. Like so,
foreach($file in $Folder)
{
...
$FileContent = Get-Content $file.FullName
Change your working directory to U:\...\Source and then it shall work.
Use
cd U:\...\Source
$folder = gci U:\...\Source
After you are done with your work, you can change your working directory again using cd command or the push-location cmdlet.
try this:
Get-ChildItem U:\...\Source -file -filter "*example*" | %{
$FileContent = Get-Content $_.fullname
}
This question already has answers here:
How to properly -filter multiple strings in a PowerShell copy script
(5 answers)
Closed 6 years ago.
I have this script and it's working 100% , but only for a single item
I want to loop the script and get content from a txt file
You see, my scipt search for a specific file and copy it to an existing folder with the same name of the file.
So what I want is to get the folder's name and the file's name from 2 txt files and loop the script
I have manage to get the content from the txt files but I can't loop the script if I add a second line with new values in my txt files.
I always get the error:
Get-ChildItem : Cannot convert 'System.Object[]' to the type
'System.String' required by parameter 'Filter'. Specified method is
not supporte d.
Ok this is my script:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
# Setup source and destination paths
$Src = '\\192.168.0.216\home\'
$Dst = 'C:\TEST\120629B\'
# Wildcard for filter
$Extension = '120629B.jpg'
# Get file objects recursively
Get-ChildItem -Path $Src -Filter $Extension -Recurse |
# Skip directories, because XXXReadMe.txt is a valid directory name
Where-Object {!$_.PsIsContainer} |
# For each file
ForEach-Object {
# If file exist in destination folder, rename it with directory tag
if(Test-Path -Path (Join-Path -Path $Dst -ChildPath $_.Name))
{
# Get full path to the file without drive letter and replace `\` with '-'
# [regex]::Escape is needed because -replace uses regex, so we should escape '\'
$NameWithDirTag = (Split-Path -Path $_.FullName -NoQualifier) -replace [regex]::Escape('\'), '-'
# Join new file name with destination directory
$NewPath = Join-Path -Path $Dst -ChildPath $NameWithDirTag
}
# Don't modify new file path, if file doesn't exist in target dir
else
{
$NewPath = $Dst
}
# Copy file
Copy-Item -Path $_.FullName -Destination $NewPath
}
Ok this is what I have change and worked but is only working with one record
$Src = '\\192.168.0.216\home\'
$Dst = Get-Content 'C:\TEST\path.txt'
# Wildcard for filter
$Extension = Get-Content 'C:\TEST\file.txt'
The error message is telling you the problem, you can't use an array as the filter for get-childitem. you can probably nest a where-object filter inside of a foreach loop but the easiest way to accomplish what you are trying to do is going to be to loop through your extension filters and then run your loop inside of that loop. so wrap your entire Get-ChildItem loop in a Foreach loop as below.
Foreach($e in $extension){
*Your Code Here*
}
Of cource make sure to change the -Filter parameter of your Get-ChildItem from $Extension to $e
Like error says, -Filter expects a single string. Get-Content would be returning an object array for files with more than one line.
Since you are also using -Recurse consider using -Include instead of -Filter since it supports arrays of stings. This should without changing your input file or adding any other post processing. From [MSDN]
Specifies, as a string array, an item or items that this cmdlet includes in the operation. The value of this parameter qualifies the Path parameter. Enter a path element or pattern, such as *.txt. Wildcards are permitted.
Get-ChildItem -Path $Src -Include $Extension -Recurse
Note:
The Include parameter is effective only when the command includes the Recurse parameter or the path leads to the contents of a directory, such as C:\Windows*, where the wildcard character specifies the contents of the C:\Windows directory.
Same goes for -Exclude as well
I have the directory E:\NugetRoot\NugetServer where I need to cycle through the subdirectories on this path and within the packages folder within that subdirectory I need to count the files ending in .nupkg and output them to a cvs file named d:\monitoring\NugetStatistics and each time the script is run, it should append to the file.
Count the files ending in .nupkg in "C:\NugetRoot\NugetServer\\**\Packages" for each folder. (I need to Loop through the ** folders and count each file ending on .nupkg)
Output in cvs file with two columns: one showing the "**" folder name & the other showing the file count.
First find all the *.nupkg files using Get-Childitem with the recurse flag to get all files in sub folders, then filter the results using a regex to exclude any where the final folder is not called Package. Then use another regex to extract the previous folder name, feed that in to a Group-Object to get the count and then into a Export-Csv which includes the append flag.
cd E:\NugetRoot\NugetServer
Get-ChildItem -Filter *.nupkg -Recurse | ? {
$_.DirectoryName -match '\\Packages$'
} | % {
$_.DirectoryName -Replace '^.*\\([^\\]+)\\Packages$', '$1'
} | Group-Object | Select Name, Count | Export-Csv outfile.csv -Append -NoTypeInformation
cd "C:\NugetRoot\NugetServer\\**\Packages"
$a = Get-ChildItem -Name
foreach ($i in $a) {
$b = (Get-ChildItem -Recurse -Force -Include .nupkg -Path $i | Select-Object -ExpandProperty Name).Count
$i + "`t" + $b
}
Here's what I have so far. It displays the server name, ProjectgroupID(or folder name), but get error for package count. Also, I am having trouble getting the average file size as well, I commented those out:
$folders = gci C:\NuGetRoot\NugetServer -Directory
foreach($folder in $folders){
#{ServerName=$env:COMPUTERNAME;
ProjectGroupID = $folder.Name;
NuGetPackageCount = (gci $folder.FullName\packages -Include '*.nupkg') | %{$_.Size}.Count;
#AverageSize= Measure-Object (listof sizes) -Average
} #| Export-Csv -Path c:\temp -NoTypeInformation -Append
}
Measure-Object -Average
Using powershell I would like to search through an array of sub-folders in multiple directories containing 1 folder called incoming and move the files from incoming to a staging area using the same folder name as its source.
IE: Files arrive in folders like this:
z:\folder1\incoming\file.*, z:\folder2\incoming\file.*, z:\folder3\sub1\incoming\file.*, z:\folder3\sub2\incoming\file.* etc.
Then would need to be moved to a staging area using the same folder structure:
\nas\staging\folder1\incoming\file.*, \nas\staging\folder2\incoming\file.*, \nas\staging\folder3\sub1\incoming\file.*, \nas\staging\folder3\sub2\incoming\file.* etc.
Basically the only sub-folders i want to extract from are the ones containing the "Incoming" folder with files. Since there is no predefined folder names other than the sub-folder "Incoming" i would need to loop through every folder within Z:.
Any help or advice would be greatly appreciated.
I was able to come up with this which affectively moves the folder structure excluding "outgoing" to the staging directory which is great but in my environment there would be to many exclusions to check for this way. Also is there a chance i can move the files to specific folders from maybe a list if needed?
$from = 'C:\ftp'
$to = 'C:\staging'
$excludeMatch = #("Outgoing")
Get-ChildItem -Path $from -Recurse -Exclude $exclude |
where { $excludeMatch -eq $null -or $_.FullName.Replace($from, "") -notmatch $excludeMatch } |
Copy-Item -Destination {
if ($_.PSIsContainer) {
Join-Path $to $_.Parent.FullName.Substring($from.length)
} else {
Join-Path $to $_.FullName.Substring($from.length)
}
} -Force -Exclude $exclude
Sooooo, what we need is, to identify any file whos parent directory is called 'incoming'? There are at least two ways of solving this I can think of, but there may be a neater, more idiomatic solution that eludes me.
Method 1 - Identify 'incoming' folders then copy contents
get-childitem -Path $from -recurse -Filter "incoming" |
where-object { $_.PSIsContainer }
If you are using PowerShell 3, I believe (read 'untested') this could be shortened to
get-childitem -Path $from -recurse -Filter "incoming" -Directory
Either of the above should result in a stream of 'directory' objects, all of which are 'incoming' folders. For each one, copy the files to appropriate destination.
Method 2 - Identify all files then process those whos folder is 'incoming'
get-childitem -path $from -recurse |
where-object { -not $_.PSIsContainer } |
where-object { (Split-Path $_.Directory -Leaf) -eq "incoming" }
This results in a stream of 'file' objects, all of which are in a folder called 'incoming'. For each one, copy to appropriate destination.