Home > front end >  How do I get a local path and alter it in PowerShell
How do I get a local path and alter it in PowerShell

Time:11-11

I have a local path like this C:\test\1\2\3\x\z\6\7\8 How do I insert a y folder in this hierarchy between x and z folders using PowerShell, assuming the folder names are random but the hierarchy is always the same

Tried Get-ChildItem Split-Path Split-Path Join-Path functions but didn't get the expected results...

CodePudding user response:

Use the regex-based -replace operation:

To match by position in the hierarchy:

'C:\test\1\2\3\x\z\6\7\8' -replace '(?<=^([^\\] \\){6})', 'y\'

Note:

  • For an explanation of the regex and the ability to experiment with it, see this regex 101.com page; in essence, the position after the 6 \-separated components from the start of the path is matched (via a positive look-behind assertion, (?<=...)), and the name of the new folder, followed by \, is inserted (that is, the position of the match is "replaced", resulting in effective insertion).

  • Should the real folder name (represented by y here) happen to contain $ chars., escape them as $$; see below and this answer for more information.

To match by folder names, anywhere inside the hierarchy:

'C:\test\1\2\3\x\z\6\7\8' -replace '\\(x)\\(z)\\', '\$1\y\$2\'

Note:

  • Because \ is a metacharacter in regexes, it must be escaped as \\

    • If your concrete folder names (represented by x and z here) happen to contain regex metacharacters too (say .), they too must be \-escaped; alternatively, escape the names as a whole with [regex]::Escape().
  • (...), i.e. capture groups are used to capture the surrounding folder names, so they can be referred to via placeholders $1 and $2 in the substitution expression (which itself is not a regular expression; only $ chars. are metacharacters there; literal use requires $$).

CodePudding user response:

Another way to do using a DirectoryInfo instance, a do loop to traverse it's hierarchy, Path.Combine method and a Stack:

$insertAfter    = 'x'
$folderToInsert = 'y'
$directory = [System.IO.DirectoryInfo] 'C:\test\1\2\3\x\z\6\7\8'
$segments  = [System.Collections.Stack]::new()

do {
    if($directory.BaseName -eq $insertAfter) {
        $segments.Push($folderToInsert)
    }
    $segments.Push($directory.BaseName)
    $directory = $directory.Parent
} while($directory)

[IO.Path]::Combine.Invoke([string[]] $segments)

Assuming C:\test\1\2\3\x\z\6\7\8 was a real directory, then you can use Get-Item instead:

$directory = Get-Item 'C:\test\1\2\3\x\z\6\7\8'
  • Related