locked
Appending Parent Folder, Current Folder onto file name RRS feed

  • 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

  • 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>

     

    \_(ツ)_/





    • Marked as answer by Will Law Monday, January 14, 2019 9:30 PM
    • Edited by jrv Monday, January 14, 2019 9:35 PM
    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

  • 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>

     

    \_(ツ)_/





    • Marked as answer by Will Law Monday, January 14, 2019 9:30 PM
    • Edited by jrv Monday, January 14, 2019 9:35 PM
    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