Answered by:
Appending Parent Folder, Current Folder onto file name

Question
-
Hello and thanks for any help in advance. I am tasked with figuring out a way to do something and I wasn't sure if PowerShell was even the correct tool for this but here goes. We have a network drive with several existing attachments and daily new ones are added. The users would like to see of there is a way to append the current folder name, something like 00000001, but only have the last 4 digits. They are always 8 digit long, but we only need the last four, including the leading zeros. and also append the parent folder name in front of it, separated by a dash.
Example a parent folder is 19 (for the current year) with a child folder of 00000001, then inside the child folder can be a variety of attachments such as pdf, word or outlook msg files, but our example has a PLANS.PDF and APP.MSG file and another file 19-0001 Letter.docx (this one was already renamed by hand, some users are like that).
Ideally the script will run daily and ignore those files that already have the YY-#### in the front of it and focus on appending the name.
So how on earth can we accomplish this, if PowerShell is the tool? If there is another recommended way, I am open to any suggestions. We currently have a program PFRANK that is accomplishing this task, but noone knows how to setup new ones with the program and we are worried it will sometime be no longer supported.
Wednesday, January 9, 2019 1:16 PM
Answers
-
Please carefully review the following links to set your expectation for posting in technical forums.
This Forum is for Scripting Questions Rather than script requests
- Script Gallery.
- Forum for Script requests
- How to ask questions in a technical forum
- Rubber duck problem solving
- How to write a bad forum post
- Help Vampires: A Spotter's Guide
- This forum is for scripting questions rather than script requests
\_(ツ)_/
- Marked as answer by Will Law Wednesday, January 9, 2019 4:18 PM
Wednesday, January 9, 2019 2:10 PM -
I guess that's where I am getting lost. In my original code I had {$_.Directory.Name, but it was bringing in just the current folder name, not the parent to that folder and appending it to the file name.
You said parent folder and you are working with a file object. $_.Directory IS the parent folder. $_.Directory.Parent is the parent. $_.Direcrory.Parent.Parent … etc.
$_.Directory.Parent.Name
Learn how to browser object. If you have to ask for every step in PowerShell scripting will be pointless. All of these things are discoverable in PowerShell.
PS D:\scripts> $x.Directory.GetType().Name DirectoryInfo
Now Google that and read about the object.
Browse an object:
PS D:\scripts> $x.Directory | Get-Member TypeName: System.IO.DirectoryInfo Name MemberType Definition ---- ---------- ---------- LinkType CodeProperty System.String LinkType{get=GetLinkType;} Mode CodeProperty System.String Mode{get=Mode;} Target CodeProperty System.Collections.Generic.IEnumerable``1[[System.String, msc Create Method void Create(), void Create(System.Security.AccessControl.Dir CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedTy CreateSubdirectory Method System.IO.DirectoryInfo CreateSubdirectory(string path), Sys Delete Method void Delete(), void Delete(bool recursive) EnumerateDirectories Method System.Collections.Generic.IEnumerable[System.IO.DirectoryIn EnumerateFiles Method System.Collections.Generic.IEnumerable[System.IO.FileInfo] E EnumerateFileSystemInfos Method System.Collections.Generic.IEnumerable[System.IO.FileSystemI Equals Method bool Equals(System.Object obj) GetAccessControl Method System.Security.AccessControl.DirectorySecurity GetAccessCon GetDirectories Method System.IO.DirectoryInfo[] GetDirectories(), System.IO.Direct GetFiles Method System.IO.FileInfo[] GetFiles(string searchPattern), System. GetFileSystemInfos Method System.IO.FileSystemInfo[] GetFileSystemInfos(string searchP GetHashCode Method int GetHashCode() GetLifetimeService Method System.Object GetLifetimeService() GetObjectData Method void GetObjectData(System.Runtime.Serialization.Serializatio GetType Method type GetType() InitializeLifetimeService Method System.Object InitializeLifetimeService() MoveTo Method void MoveTo(string destDirName) Refresh Method void Refresh() SetAccessControl Method void SetAccessControl(System.Security.AccessControl.Director ToString Method string ToString() Attributes Property System.IO.FileAttributes Attributes {get;set;} CreationTime Property datetime CreationTime {get;set;} CreationTimeUtc Property datetime CreationTimeUtc {get;set;} Exists Property bool Exists {get;} Extension Property string Extension {get;} FullName Property string FullName {get;} LastAccessTime Property datetime LastAccessTime {get;set;} LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;} LastWriteTime Property datetime LastWriteTime {get;set;} LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;} Name Property string Name {get;} Parent Property System.IO.DirectoryInfo Parent {get;} Root Property System.IO.DirectoryInfo Root {get;} BaseName ScriptProperty System.Object BaseName {get=$this.Name;} PS D:\scripts>
\_(ツ)_/
Monday, January 14, 2019 9:28 PM -
I finalized my script and it works as I needed in case anyone else is looking for something like this.
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
}- Marked as answer by Will Law Friday, January 18, 2019 8:18 PM
Friday, January 18, 2019 8:18 PM
All replies
-
Please carefully review the following links to set your expectation for posting in technical forums.
This Forum is for Scripting Questions Rather than script requests
- Script Gallery.
- Forum for Script requests
- How to ask questions in a technical forum
- Rubber duck problem solving
- How to write a bad forum post
- Help Vampires: A Spotter's Guide
- This forum is for scripting questions rather than script requests
\_(ツ)_/
- Marked as answer by Will Law Wednesday, January 9, 2019 4:18 PM
Wednesday, January 9, 2019 2:10 PM -
Thanks, my apologies.Wednesday, January 9, 2019 4:16 PM
-
Use the resources linked above to start writing your script. Post back with specific questions about your script.
I recommend stating with: Microsoft Virtual Academy - Getting Started with Microsoft PowerShell
\_(ツ)_/
Wednesday, January 9, 2019 4:23 PM -
Thanks for the links, though some didn't work. Not sure if it's because of our network though. :)
I have started my script with some of the resources and slowly working my way through it. So far I have it to where it will append the current folder to the front of the file name then a space. Next step is getting the parent folder name. Then seeing if I can get just the last four characters from the current folder. Then figure out a way to ignore files that already have a YY-#### in front.
Gci –recurse –file c:\users\wlawrence\desktop\script | rename-item -NewName {$_.Directory.Name+' '+$_.Name}
Friday, January 11, 2019 7:09 PM -
I have almost completed my entire script. The one piece that I am missing is figuring out how to append the two digit parent folder to the front of the name. Any help on this piece? My current script works so far.
Get-ChildItem –recurse –file c:\users\wlawrence\desktop\script\19 | Where-Object {$_.Name –notmatch ‘[0-9][0-9]-[0-9]’} | rename-item -NewName {$_.Directory.Name.SubString($_.Directory.Name.length -4, 4) + ' ' + $_.Name}
Monday, January 14, 2019 8:06 PM -
What 2 digit number?
Please post code properly formatted and with the code posting tool. What you posted is mostly unreadable.
Like this:
Get-ChildItem c:\users\wlawrence\desktop\script\19 –recurse –file | Where-Object { $_.Name –notmatch '[0-9][0-9]-[0-9]' } | ForEach-Object{ $newname = '{0} {1}' -f $_.Directory.Name.SubString($_.DirectoryName.Length - 4, 4), $_.Name Write-Host $newname -fore green rename-item -NewName $newname }
Notice how much easier this is to read and understand. It is also much easier to debug and edit.
\_(ツ)_/
- Edited by jrv Monday, January 14, 2019 8:24 PM
Monday, January 14, 2019 8:14 PM -
Sorry, new to this. So basically the | or {} is where I should put returns?
The 2 digit number is the parent folder that the current folder is located in. The structure goes Year Folder > Current Folder > File. So I have 18 and 19 year folders, within it, it has folders that have 8 digit folders. Within this has all kinds of files. So for example I need to append 18-0001 to Plans.txt. I am having a time figuring out how to pull in the parent folder. I have it doing the current folder, so it's putting 0001 Plans.txt.
Monday, January 14, 2019 8:18 PM -
This can be even better:
Get-ChildItem –recurse –file | Where-Object { $_.Name –match '\d{4,4}$' } | ForEach-Object{ $newname = '{0} {1}' -f [Text.Encoding]::ASCII.GetString($_.DirectoryName[-4..-1]), $_.Name Write-Host $newname -fore green rename-item -NewName $newname }
\_(ツ)_/
- Edited by jrv Monday, January 14, 2019 8:28 PM
Monday, January 14, 2019 8:25 PM -
Wow, looks like that would do it. How do I tell it which folder I want to begin looking into for naming the files though? In my code, I specifically put in the C:\users\wlawrence\desktop\script\19 because I will need to do this on specific folders in a larger directory.
I assume that the #newname = {0}{1}' -f the 0 equals the current folder, the 1 is up one level?
Thank you so much for your patience with this. New to coding so searching your links and Google for solutions.
Monday, January 14, 2019 8:33 PM -
Sorry, new to this. So basically the | or {} is where I should put returns?
The 2 digit number is the parent folder that the current folder is located in. The structure goes Year Folder > Current Folder > File. So I have 18 and 19 year folders, within it, it has folders that have 8 digit folders. Within this has all kinds of files. So for example I need to append 18-0001 to Plans.txt. I am having a time figuring out how to pull in the parent folder. I have it doing the current folder, so it's putting 0001 Plans.txt.
The parent folder of a file is $file.DirectoryName or $file.Directory.Name. $file can be $_.
Get-ChildItem c:\users\wlawrence\desktop\script\19 –recurse –file | Where-Object { $_.Name –notmatch '[0-9][0-9]-[0-9]' } | ForEach-Object{ $newname = '{0} {1}' -f $_.Directory.Name, $_.Name Write-Host $newname -fore green rename-item -Path $_ -NewName $newname }
\_(ツ)_/
- Edited by jrv Monday, January 14, 2019 8:42 PM
Monday, January 14, 2019 8:37 PM -
I guess that's where I am getting lost. In my original code I had {$_.Directory.Name, but it was bringing in just the current folder name, not the parent to that folder and appending it to the file name.Monday, January 14, 2019 8:46 PM
-
I guess that's where I am getting lost. In my original code I had {$_.Directory.Name, but it was bringing in just the current folder name, not the parent to that folder and appending it to the file name.
You said parent folder and you are working with a file object. $_.Directory IS the parent folder. $_.Directory.Parent is the parent. $_.Direcrory.Parent.Parent … etc.
$_.Directory.Parent.Name
Learn how to browser object. If you have to ask for every step in PowerShell scripting will be pointless. All of these things are discoverable in PowerShell.
PS D:\scripts> $x.Directory.GetType().Name DirectoryInfo
Now Google that and read about the object.
Browse an object:
PS D:\scripts> $x.Directory | Get-Member TypeName: System.IO.DirectoryInfo Name MemberType Definition ---- ---------- ---------- LinkType CodeProperty System.String LinkType{get=GetLinkType;} Mode CodeProperty System.String Mode{get=Mode;} Target CodeProperty System.Collections.Generic.IEnumerable``1[[System.String, msc Create Method void Create(), void Create(System.Security.AccessControl.Dir CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedTy CreateSubdirectory Method System.IO.DirectoryInfo CreateSubdirectory(string path), Sys Delete Method void Delete(), void Delete(bool recursive) EnumerateDirectories Method System.Collections.Generic.IEnumerable[System.IO.DirectoryIn EnumerateFiles Method System.Collections.Generic.IEnumerable[System.IO.FileInfo] E EnumerateFileSystemInfos Method System.Collections.Generic.IEnumerable[System.IO.FileSystemI Equals Method bool Equals(System.Object obj) GetAccessControl Method System.Security.AccessControl.DirectorySecurity GetAccessCon GetDirectories Method System.IO.DirectoryInfo[] GetDirectories(), System.IO.Direct GetFiles Method System.IO.FileInfo[] GetFiles(string searchPattern), System. GetFileSystemInfos Method System.IO.FileSystemInfo[] GetFileSystemInfos(string searchP GetHashCode Method int GetHashCode() GetLifetimeService Method System.Object GetLifetimeService() GetObjectData Method void GetObjectData(System.Runtime.Serialization.Serializatio GetType Method type GetType() InitializeLifetimeService Method System.Object InitializeLifetimeService() MoveTo Method void MoveTo(string destDirName) Refresh Method void Refresh() SetAccessControl Method void SetAccessControl(System.Security.AccessControl.Director ToString Method string ToString() Attributes Property System.IO.FileAttributes Attributes {get;set;} CreationTime Property datetime CreationTime {get;set;} CreationTimeUtc Property datetime CreationTimeUtc {get;set;} Exists Property bool Exists {get;} Extension Property string Extension {get;} FullName Property string FullName {get;} LastAccessTime Property datetime LastAccessTime {get;set;} LastAccessTimeUtc Property datetime LastAccessTimeUtc {get;set;} LastWriteTime Property datetime LastWriteTime {get;set;} LastWriteTimeUtc Property datetime LastWriteTimeUtc {get;set;} Name Property string Name {get;} Parent Property System.IO.DirectoryInfo Parent {get;} Root Property System.IO.DirectoryInfo Root {get;} BaseName ScriptProperty System.Object BaseName {get=$this.Name;} PS D:\scripts>
\_(ツ)_/
Monday, January 14, 2019 9:28 PM -
I finalized my script and it works as I needed in case anyone else is looking for something like this.
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
}- Marked as answer by Will Law Friday, January 18, 2019 8:18 PM
Friday, January 18, 2019 8:18 PM