{"id":8071,"date":"2007-04-27T17:39:00","date_gmt":"2007-04-27T17:39:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2007\/04\/27\/fun-with-paths\/"},"modified":"2019-02-18T13:16:42","modified_gmt":"2019-02-18T20:16:42","slug":"fun-with-paths","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/fun-with-paths\/","title":{"rendered":"Fun with Paths"},"content":{"rendered":"<p class=\"MsoNormal\"><span>Jeffrey wrote a <a href=\"http:\/\/blogs.msdn.com\/powershell\/archive\/2007\/04\/14\/controlling-the-scope-of-variables.aspx\"><span>great post<\/span><\/a> for wizards about the scope of variables in PowerShell, so to maintain balance, I thought I&#8217;d weigh in with one for newbies. (Although, to be honest, Jeffrey&#8217;s description is clear enough for the rest of us.) <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>There are some newbies here, right?<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>In a thread about Move-Item on <a href=\"http:\/\/www.microsoft.com\/communities\/newsgroups\/list\/en-us\/default.aspx?dg=microsoft.public.windows.powershell\"><span>Microsoft.Public.Windows.PowerShell<\/span><\/a>, PowerShell tester-extraordinaire Marcel Ortiz Soto suggested a clever method for deleting the current directory from a path. You might want to study this method and store it away for future use. <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>As a bonus, it shows how do string manipulation on PathInfo and FileInfo objects. Essentially, you use string methods on the string properties of these non-string objects. (Easier done than said\u2026)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>By the way, Marcel&#8217;s solution uses the $pwd automatic variable, which always contains the path to the current directory. <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>PS C:\\Windows&gt; $pwd<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Path<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;-<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>C:\\Windows<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>$pwd is missing from the version of about_automatic_variables shipped with Windows PowerShell 1.0, but it will appear in updates. Sorry about that.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><b><span>The Problem<\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>A user wanted to move selected files from one directory to another while preserving their directory structure. Because the files were being piped to Move-Item one at a time from a Get-ChildItem command, the directory structure was lost.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>The solution was to specify a new directory path for each file that consisted of a new location, but the current subdirectories and file name.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>The original path:<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><b>C:\\Windows<\/b>\\&lt;subdirectories\\filename&gt;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>The new path:<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><b>D:\\Archive<\/b>\\&lt;subdirectories\\filename&gt;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>The task is to remove the current directory (C:\\Windows) from the path and append the remainder of the path to D:\\Archive.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><b><span>The<span>&nbsp; <\/span>Solution<\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>Here is Marcel&#8217;s solution:<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>get-childitem | where {<i>condition<\/i>s} | move-item -destination {join-path &#8216;D:\\Archive&#8217;&nbsp;$_.FullName.SubString($pwd.path.length) }<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><b><span>The Method: Eliminate the current directory from a path<\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>My first inclination was to use the Split-Path cmdlet to eliminate the current directory part of the path, but it doesn&#8217;t let you distinguish between parts of a &#8220;Parent&#8221; path. Thus, the solution requires some string manipulation. <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>To delete the current directory from a file or directory path:<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span>Find the length (the number of characters) of the current directory path. Use the Length property of the path, which is a string.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; PS C:\\Windows&gt; $pwd&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span>&nbsp; <\/span># a PathInfo object<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; Path<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; &#8212;-<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; C:\\Windows<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; PS C:\\Windows&gt; $pwd.path&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; # a string<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; C:\\Windows<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; PS C:\\Windows&gt; $pwd.path.length&nbsp; &nbsp;<span>&nbsp; <\/span># the length of the path string<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp; &nbsp; 10<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>(HINT: $pwd is a PathInfo object, so it doesn&#8217;t have a Length property, but its Path property is a string, which does have a Length property.)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span>Find the original, fully-qualified path of the file, which includes the current directory. Use the FullName property of the file (or directory), which is a string.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>PS C:\\Windows&gt; get-item C:\\Windows\\Dev\\tmp.txt<span>&nbsp; <\/span><span>&nbsp;&nbsp;<\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span># FileInfo object<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>PS C:\\Windows&gt; (get-item C:\\Windows\\Dev\\tmp.txt).fullname C:\\Windows\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>(HINT: We use FullName property to get a string object that contains the file path. This allows us to do the next step, which requires a string.)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><span>Use the SubString method on the FullName property of the original file path. The SubString method eliminates the specified number of characters, and then returns the remainder of the string. <\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>For the value of substring, that is, the number of characters to eliminate, use $pwd.path.length which represents the number of characters in the current directory path.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&lt;File&gt;.FullName.Substring(&lt;length-of-current-directory-path&gt;)&nbsp; &nbsp;<span>&nbsp; <\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>PS C:\\Windows&gt;(get-item C:\\Windows\\Dev\\tmp.txt).FullName.SubString($pwd.path.length)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>In essence, we take the original path in string form (its FullName):<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>C:\\Windows\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>Then we eliminate the number of characters in the path to the current directory ($pwd.path.length = 10 characters).<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>C:\\Windows\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>And return the remainder of the string (the &#8220;substring&#8221;):<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>(HINT: You can&#8217;t use the SubString method on the file path, which is a FileInfo object, but you can use it on the value of the FullName property of the FileInfo object, which is a string.)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>For more information about the <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa904307(VS.71).aspx\">Substring<\/a> method, see:&nbsp; &nbsp; &nbsp; &nbsp;<span>&nbsp; <\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<span>&nbsp; <\/span><a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa904307(VS.71).aspx\">http:\/\/msdn2.microsoft.com\/en-us\/library\/aa904307(VS.71).aspx<\/a>.)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><b><span>Create a New Path&nbsp; &nbsp; <\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>The final step is to append the remainder of the path to the new location, D:\\Archive.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>In this case, Marcel used the Join-Path cmdlet to create a new path. He appended the remainder of the file path to a new path header, D:\\Archive:<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>PS C:\\Windows&gt; join-path -path &lt;NewPath&gt; -Childpath &lt;path-substring&gt;<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>PS C:\\Windows&gt; join-path -path D:\\Archive -childpath (get-item C:\\Windows\\Dev\\tmp.txt).FullName.SubString($pwd.path.length)<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>D:\\Archive\\Dev\\tmp.txt<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>This was a great solution for this task, but it&#8217;s also a great strategy for many different tasks. It&#8217;s a neat twist on Split-Path.<\/span><\/p>\n<p class=\"MsoNormal\"><span>&nbsp;<\/span><\/p>\n<p class=\"MsoNormal\"><span>June Blender [MSFT]<\/span><\/p>\n<p class=\"MsoNormal\"><span>Windows PowerShell Documentation<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jeffrey wrote a great post for wizards about the scope of variables in PowerShell, so to maintain balance, I thought I&#8217;d weigh in with one for newbies. (Although, to be honest, Jeffrey&#8217;s description is clear enough for the rest of us.) &nbsp; There are some newbies here, right? &nbsp; In a thread about Move-Item on [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-8071","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"blog_post_summary":"<p>Jeffrey wrote a great post for wizards about the scope of variables in PowerShell, so to maintain balance, I thought I&#8217;d weigh in with one for newbies. (Although, to be honest, Jeffrey&#8217;s description is clear enough for the rest of us.) &nbsp; There are some newbies here, right? &nbsp; In a thread about Move-Item on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/8071","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=8071"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/8071\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=8071"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=8071"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=8071"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}