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
}
Related
I have a script that runs when I specify the exact directory of c:\script\19\ the problem is, have other folders in the c:\script such as 18, 17, 16. The script I have is appending the 19 in front of all of the files. How do I get this to look at the grandparent of the file it's renaming and append it? An example of how it's working is files like this:
c:\script\18\00000001\Plans.txt
c:\script\19\00001234\Plans.txt
c:\script\17\00005678\App.txt
But my script is renaming the files like this
c:\script\18\00000001\19-0001 Plans.txt
c:\script\19\00001234\19-1234 Plans.txt
c:\script\17\00005678\19-5678 App.txt
My script is this:
$filepath = Get-ChildItem "C:script\" -Recurse |
ForEach-Object {
$parent = $_.Parent
$grandparent = $_.fullname | Split-Path -Parent | Split-Path -Parent | Split-Path -Leaf
}
Get-ChildItem "C:\Script\" –recurse –file |
Where-Object {$_.Name –notmatch ‘[0-9][0-9]-[0-9]’} |
rename-item -NewName {$grandparent + '-' + $_.Directory.Name.SubString($_.Directory.Name.length -4, 4) + ' ' + $_.Name}
The simplest solution is to combine string-splitting with the -split operator with a delay-bind script block (which you've tried to use):
Get-ChildItem C:\Script –Recurse –File -Exclude [0-9][0-9]-[0-9]* |
Rename-Item -NewName {
# Split the full path into its components.
$names = $_.FullName -split '\\'
# Compose the new file name from the relevant components and output it.
'{0}-{1} {2}' -f $names[-3], $names[-2].Substring($names[-2].Length-4), $_.Name
} -WhatIf
-WhatIf previews the renaming operation; remove it to perform actual renaming.
Note how -Exclude is used with a wildcard expression directly with Get-ChildItem to exclude files that already have the target name format.
The main reason your original didn't work is that you calculated single, static
$parent and $grandparent values, instead of deriving the input path-specific values from each input path.
Additionally, your $grandparent calculation was needlessly complicated; Gert Jan Kraaijeveld's helpful answer shows a simpler way.
To get the grandparent of a $file object:
$file.Directory.Parent
The parent directory of a file is the 'Directory' member of the file object.
The parent directory of a directory is the 'Parent' member of the directory object.
It is not hard, but confusing it sure is...
Edit
You asked for my solution:
Get-ChildItem C:\script -Recurse -File | ForEach-Object {
$parent = $_.Directory.Name
$grandparent = $_.Directory.Parent.Name
Rename-Item $_.FullName -NewName "$grandparent-$($parent.Substring($parent.length-4,4)) $($_.name)"
}
I used the -file parameter of Get-ChildItem to get only files from the folder structure. I'm not sure that suits in your situation
I have a powershell script that takes the list of folders in a directory and zips the latest .bak file and copies it into another directory.
There are two folders that I do not want it to look in for the .bak files. How do I exclude these folders? I have tried multiple ways of -Exclude statements and I haven't had any luck.
The folders I would like to ignore are "New folder" and "New folder1"
$source = "C:\DigiHDBlah"
$filetype = "bak"
$list=Get-ChildItem -Path $source -ErrorAction SilentlyContinue
foreach ($element in $list) {
$fn = Get-ChildItem "$source\$element\*" -Include "*.$filetype" | sort LastWriteTime | select -last 1
$bn=(Get-Item $fn).Basename
$CompressedFile=$bn + ".zip"
$fn| Compress-Archive -DestinationPath "$source\$element\$bn.zip"
Copy-Item -path "$source\$element\$CompressedFile" -Destination "C:\DigiHDBlah2"
}
Thank you!
What I would do is use the Directory property on the files that you find, and the -NotLike operator to do a simple match for the folders you don't want. I would also simplify the search by using a wildcard:
$Dest = "C:\DigiHDBlah2"
$files = Get-ChildItem "$source\*\*.$filetype" | Where{$_.Directory -NotLike '*\New Folder' -and $_.Directory -NotLike '*\New Folder1'} | Sort LastWriteTime | Group Directory | ForEach{$_.Group[0]}
ForEach($file in $Files){
$CompressedFilePath = $File.FullName + ".zip"
$file | Compress-Archive -DestinationPath $CompressedFilePath
Copy-Item $CompressedFilePath -Dest $Dest
}
Or, if you want to just supply a list of folders to exclude you could do a little string manipulation on the directoryName property to just get the last folder, and see if it is in a list of excludes like:
$Excludes = #('New Folder','New Folder1')
$Dest = "C:\DigiHDBlah2"
$files = Get-ChildItem "$source\*\*.$filetype" | Where{$_.DirectoryName.Split('\')[-1] -NotIn $Excludes} | Sort LastWriteTime | Group Directory | ForEach{$_.Group[0]}
ForEach($file in $Files){
$CompressedFilePath = $File.FullName + ".zip"
$file | Compress-Archive -DestinationPath $CompressedFilePath
Copy-Item $CompressedFilePath -Dest $Dest
}
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")
I have this piece of powershell code below which creates an individual text file in the folder C:\Users\XX\Desktop\info\ from each individual zip file in the folder C:\Users\XX\Desktop\Powershell\Zip, with the name of the text files being the name of the zip files.
Get-ChildItem -Path "C:\Users\XX\Desktop\Powershell\Zip" -Recurse -exclude '*.info' | ForEach { [System.IO.File]::WriteAllText("C:\Users\XX\Desktop\info\"+ $_.Name + ".txt", $_.FullName)}
ontop of that I have the script below which gets the last modified date for the zip files
$path = 'C:\Users\XX\Desktop\Powershell\Zip'
$files = Get-ChildItem $path -Recurse -excluse '*.info'
foreach($file in $files){
$file.lastwritetime
and also this command that gets the computer name
{
(Get-WmiObject Win32_Computersystem).name
}
All these will be in one script, but I need the outputs of the 2nd and 3rd section of the script to append to the text file created in the first section of the script, appending to the appropriate file.
I have tried a couple of commands, the main one being [System.IO.File]::AppendAllText, but I cant seem to get anywhere with this.
Any ideas on the right way I should be doing this?
Thankyou.
You can try this :
$path = 'C:\Users\XX\Desktop\Powershell\Zip'
$files = Get-ChildItem $path -Recurse -Exclude '*.info'
$ComputerName = (Get-WmiObject Win32_Computersystem).name
foreach($file in $files) {
$OutputFilePath = "C:\Users\XX\Desktop\info\"+ $file.Name + ".txt"
[System.IO.File]::WriteAllText($OutputFilePath, $file.FullName)
$file.lastwritetime | Add-Content $OutputFilePath
$ComputerName | Add-Content $OutputFilePath
}
I have 10K documents in a directory with this type of naming convention:
1050_14447_Letter Extension.pdf, 1333_14444_Letter.docx, etc...
I tried using this script to remove all characters before the 2nd underscore (including the 2nd underscore):
Get-ChildItem -Filter *.pdf | Rename-Item -NewName {$_.Name -replace '^[0-9_]+'}
This worked, but revealed there would be duplicate file names.
Wondering if there is some way a script can create a subfolder based on the filename (minus the extension)? So there would be 10K subfolders in my main folder. Each subfolder would just have the one file.
This should work. It creates a new folder for each item, then moves it, renaming it in the process.
gci | ? {!$_.PSIsContainer} | % {New-Item ".\$($_.BaseName)" -Type Directory; Move-Item $_ ".\$($_.BaseName)\$($_.Name -replace '^[0-9_]+')"}
Note that if there are two files with the same name, but different extensions, you'll see an error when trying to create the directory, but both files will wind up in the same folder.
Alternately, if you want something more readable to save in a script, this is functionally identical:
$files = Get-ChildItem | Where-Object {!$_.PSIsContainer}
foreach ($file in $files)
{
$pathName = ".\" + $file.BaseName
New-Item $pathName -Type Directory
$newFileName = $pathName + "\" + ($file.Name -replace '^[0-9_]+')
Move-Item $file $newFileName
}