Get a specific folder name from path - powershell

How to get the 4th folder name and store it in a variable while looping through the files stored in a parent folder. For example, if the path is
C:\ParentFolder\Subfolder1\subfolder2\subfolder3\file.extension
C:\ParentFolder\Subfolder1\subfolder2\subfolder4\file.extension
C:\ParentFolder\Subfolder1\subfolder2\subfolder5\file.extension
then subfolder2 name should be stored in a variable. Can any one please help me on this?
get-childitem $DirectorNane -Recurse | Where-Object{!($_.PSIsContainer)} | % {
$filePath = $_.FullName
#Get file name
$fileName = Split-Path -Path $filePath -Leaf
} $FileI = Split-Path -Path $filePath -Leaf
Thanks in advance!

You can use the -split operator on the $filePath variable to get what you want.
$split = $filePath -split '\\'
$myvar = $split[3]
We use the double backslash to split with, because the first slash escapes the slash character to split the path by. Then, we can reference the part of the path we want in the array that gets generated in the "split" variable.
Additionally, you can solve this with a one liner using the following code:
$myvar = $filepath.split('\')[3]
This would ensure that you're always getting the fourth element in the array, but is a little less flexible since you can't specify what exactly you want based on conditions with additional scripting.

If you are asking how to get the parent directory of the directory containing a file, you can call Split-Path twice. Example:
$filePath = "C:\ParentFolder\Subfolder1\subfolder2\subfolder3\file.extension"
$parentOfParent = Split-Path (Split-Path $filePath)
# $parentOfParent now contains "C:\ParentFolder\Subfolder1\subfolder2"

Related

How do I remove a "base" portion of a path?

I have a series of folders in a source directory that I need to recreate in another environment. The source folder look like this:
C:\temp\stuff\folder01\
C:\temp\stuff\folder02\
C:\temp\stuff\folder03\
C:\temp\stuff\folder02\dog
C:\temp\stuff\folder02\cat
I need to remove the base portion of the path - C:\temp\stuff - and grab the rest of t he path to concatenate with the destination base folder in order to create the folder structure somewhere else.
I have following script. The problem seems to be with the variable $DIR. $DIR never gets assigned the expected "current path minus the base path".
The variable $tmp is assigned something close to the expected folder name. It contains the folder name minus vowels, is split across multiple lines, and includes a bunch of leading whitespace. For example, a folder named folder01 would look like the following:
f
ld
r01
Here's the PowerShell script:
$SOURCES_PATH = "C:\temp\stuff"
$DESTINATION_PATH = "/output001"
Get-ChildItem "$SOURCES_PATH" -Recurse -Directory |
Foreach-Object {
$tmp = $_.FullName.split("$SOURCES_PATH/")
$DIR = $_.FullName.split("$SOURCES_PATH/")[1]
$destination = "$DESTINATION_PATH/$DIR"
*** code omitted ***
}
I suspect the $DIR appears to be unassigned because the [1] element is whitespace but I'm don't know why there is whitespace and what's happening to the folder name.
What's going on and how do I fix this?
String.Split("somestring") will split on every occurrence of any of the characters in "somestring", which is why you're seeing the paths being split into many more parts than you're expecting.
I'd suggest using -replace '^base' to remove the leading part of the path:
$SOURCES_PATH = "C:\temp\stuff"
$DESTINATION_PATH = "/output001"
Get-ChildItem "$SOURCES_PATH" -Recurse -Directory |Foreach-Object {
# This turns "C:\temp\stuff\folder01" into "\folder01"
$relativePath = $_.FullName -replace "^$([regex]::Escape($SOURCES_PATH))"
# This turns "\folder01" into "/folder01"
$relativeWithForwardSlash = $relativePath.Replace('\','/')
# Concatenate destination root and relative path
$rootedByDestination = "${DESTINATION_DIR}${relativeWithForwardSlash}"
# Create/Copy $rootedByDestination here
}
-replace is a regular expression operator, which is why I run [regex]::Escape() against the input path, to double-escape the backslashes :)
Consider replacing the source path with an empty string. Then you can either concat what's left onto destination path, or use Path::Combine to take care of the concatenation and any separator drama.
Source:
Get-ChildItem | ForEach-Object {
$destination = [System.IO.Path]::Combine($DESTINATION_PATH, $_.FullName.Replace($SOURCES_PATH, ''))
}

Extract the filename from a path

I want to extract filename from below path:
D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv
Now I wrote this code to get filename. This working fine as long as the folder level didn't change. But in case the folder level has been changed, this code need to rewrite. I looking a way to make it more flexible such as the code can always extract filename regardless of the folder level.
($outputFile).split('\')[9].substring(0)
If you are ok with including the extension this should do what you want.
$outputPath = "D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv"
$outputFile = Split-Path $outputPath -leaf
Use .net:
[System.IO.Path]::GetFileName("c:\foo.txt") returns foo.txt.
[System.IO.Path]::GetFileNameWithoutExtension("c:\foo.txt") returns foo
Using the BaseName in Get-ChildItem displays the name of the file and and using Name displays the file name with the extension.
$filepath = Get-ChildItem "E:\Test\Basic-English-Grammar-1.pdf"
$filepath.BaseName
Basic-English-Grammar-1
$filepath.Name
Basic-English-Grammar-1.pdf
Find a file using a wildcard and get the filename:
Resolve-Path "Package.1.0.191.*.zip" | Split-Path -leaf
$(Split-Path "D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv" -leaf)
Get-ChildItem "D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv"
|Select-Object -ExpandProperty Name
You could get the result you want like this.
$file = "D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv"
$a = $file.Split("\")
$index = $a.count - 1
$a.GetValue($index)
If you use "Get-ChildItem" to get the "fullname", you could also use "name" to just get the name of the file.
Just to complete the answer above that use .Net.
In this code the path is stored in the %1 argument (which is written in the registry under quote that are escaped: \"%1\" ). To retrieve it, we need the $arg (inbuilt arg). Don't forget the quote around $FilePath.
# Get the File path:
$FilePath = $args
Write-Host "FilePath: " $FilePath
# Get the complete file name:
$file_name_complete = [System.IO.Path]::GetFileName("$FilePath")
Write-Host "fileNameFull :" $file_name_complete
# Get File Name Without Extension:
$fileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension("$FilePath")
Write-Host "fileNameOnly :" $fileNameOnly
# Get the Extension:
$fileExtensionOnly = [System.IO.Path]::GetExtension("$FilePath")
Write-Host "fileExtensionOnly :" $fileExtensionOnly
You can try this:
[System.IO.FileInfo]$path = "D:\Server\User\CUST\MEA\Data\In\Files\CORRECTED\CUST_MEAFile.csv"
# Returns name and extension
$path.Name
# Returns just name
$path.BaseName
$file = Get-Item -Path "c:/foo/foobar.txt"
$file.Name
Works with both relative and absolute paths

Get file name only from a given path

I have a file which will have full path of files. For example:
servername\xyz\abc.txt
servername\pqr\ab1.txt
I need to get only file name (abc.txt and ab1.txt) using PowerShell.
Instead of using the resources getting the file you can use Split-Path on each line item. -Leaf is the switch needed to return just the file name.
PS M:\Scripts> split-path "servername\pqr\ab1.txt" -Leaf
ab1.txt
If you had this information in a file you could iterate through all the entires
$fileName = Get-Content fullfilepaths.txt | ForEach-Object{split-path $_ -Leaf}
Another
A simple one that would also work ( Not sure if the performance is different ) would be to use split and return the last element.
("servername\pqr\ab1.txt".Split("\"))[-1]
PSH$ $file = Get-ChildItem "servername\pqr\ab1.txt"
PSH$ $file.Name
PSH$ $file.Name
should return ab1.txt

Powershell Copying files with varying folders in the path

Right up front apologies for my lack of knowledge with Powershell. Very new to the language . I need to copy some files located in a certain path to another similar path. For example:
C:\TEMP\Users\<username1>\Documents\<varyingfoldername>\*
C:\TEMP\Users\<username2>\Documents\<varyingfoldername>\*
C:\TEMP\Users\<username3>\Documents\<varyingfoldername>\*
C:\TEMP\Users\<username4>\Documents\<varyingfoldername>\*
etc....
to
C:\Files\Users\<username1>\Documents\<varyingfoldername>\*
C:\Files\Users\<username2>\Documents\<varyingfoldername>\*
C:\Files\Users\<username3>\Documents\<varyingfoldername>\*
C:\Files\Users\<username4>\Documents\<varyingfoldername>\*
etc....
So basically all files and directories from path one need to be copied to the second path for each one of the different paths. The only known constant is the first part of the path like C:\TEMP\Users...... and the first part of the destination like C:\Files\Users.....
I can get all the different paths and files by using:
gci C:\TEMP\[a-z]*\Documents\[a-z]*\
but I am not sure how to then pass what's found in the wildcards so I can use them when I do the copy. Any help would be appreciated here.
This should work:
Get-ChildItem "C:\TEMP\*\Documents\*" | ForEach-Object {
$old = $_.FullName
$new = $_.FullName.Replace("C:\TEMP\Users\","C:\Files\Users\")
Move-Item $old $new
}
For additional complexity in matching folder levels, something like this should work:
Get-ChildItem "C:\TEMP\*\Documents\*" -File | ForEach-Object {
$old = $_.FullName
$pathArray = $old.Split("\") # Splits the path into an array
$new = [system.String]::Join("\", $pathArray[0..1]) # Creates a starting point, in this case C:\Temp
$new += "\" + $pathArray[4] # Appends another folder level, you can change the index to match the folder you're after
$new += "\" + $pathArray[6] # You can repeat this line to keep matching different folders
Copy-Item -Recurse -Force $old $new
}

How to get the Parent's parent directory in Powershell?

So if I have a directory stored in a variable, say:
$scriptPath = (Get-ScriptDirectory);
Now I would like to find the directory two parent levels up.
I need a nice way of doing:
$parentPath = Split-Path -parent $scriptPath
$rootPath = Split-Path -parent $parentPath
Can I get to the rootPath in one line of code?
Version for a directory
get-item is your friendly helping hand here.
(get-item $scriptPath ).parent.parent
If you Want the string only
(get-item $scriptPath ).parent.parent.FullName
Version for a file
If $scriptPath points to a file then you have to call Directory property on it first, so the call would look like this
(get-item $scriptPath).Directory.Parent.Parent.FullName
Remarks
This will only work if $scriptPath exists. Otherwise you have to use Split-Path cmdlet.
I've solved that like this:
$RootPath = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
You can split it at the backslashes, and take the next-to-last one with negative array indexing to get just the grandparent directory name.
($scriptpath -split '\\')[-2]
You have to double the backslash to escape it in the regex.
To get the entire path:
($path -split '\\')[0..(($path -split '\\').count -2)] -join '\'
And, looking at the parameters for split-path, it takes the path as pipeline input, so:
$rootpath = $scriptpath | split-path -parent | split-path -parent
You can use
(get-item $scriptPath).Directoryname
to get the string path or if you want the Directory type use:
(get-item $scriptPath).Directory
You can simply chain as many split-path as you need:
$rootPath = $scriptPath | split-path | split-path
simplest solution
Here's the simplest solution
"$path\..\.."
If you want to get an absolute path, you can
"$path\..\.." | Convert-Path
reusable solution
Here is a reusable solution, first define the getParent function, then call it directly.
function getParent($path, [int]$deep = 1) {
$result = $path | Get-Item | ForEach-Object { $_.PSIsContainer ? $_.Parent : $_.Directory }
for ($deep--; $deep -gt 0; $deep--) { $result = getParent $result }
return $result
}
getParent $scriptPath 2
In PowerShell 3, $PsScriptRoot or for your question of two parents up,
$dir = ls "$PsScriptRoot\..\.."
Split-Path -Path (Get-Location).Path -Parent
To extrapolate a bit on the other answers (in as Beginner-friendly a way as possible):
String objects that point to valid paths can be converted to DirectoryInfo/FileInfo objects via functions like Get-Item and Get-ChildItem.
.Parent can only be used on a DirectoryInfo object.
.Directory converts a FileInfo object to a DirectoryInfo object (targeting the file's directory), and will return null if used on any other type (even another DirectoryInfo object).
.DirectoryName converts a FileInfo object to a String object (targeting the file's directory), and will return null if used on any other type (even another String object).
.FullName converts a DirectoryInfo/FileInfo object to a String object, and will return null if used on any other type (even another DirectoryInfo/FileInfo object).
.Path converts a PathInfo object to a String object, and will return null if used on any other type (even another PathInfo object).
Check the object type with the GetType Method to see what you're working with: $scriptPath.GetType()
Lastly, a quick tip that helps with making one-liners: Get-Item has the gi alias and Get-ChildItem has the gci alias.
If you want to use $PSScriptRoot you can do
Join-Path -Path $PSScriptRoot -ChildPath ..\.. -Resolve
In powershell :
$this_script_path = $(Get-Item $($MyInvocation.MyCommand.Path)).DirectoryName
$parent_folder = Split-Path $this_script_path -Leaf