powershellpathdirectorysubdirectory

Correctly create the path without taking the whole path name but only from the current one in Powershell


I have this script that does not apply correctly to the subfolders. It should create the files all inside the folder "Txt_ENG" respecting the subfolders.

Example:

I am in:

G:\Games\Files here

the file abc.csv is located in:

G:\Games\Files here\current\csv

the file abc.txt needs to be created in:

G:\Games\Files here\Txt_ENG\current\csv

Where it creates it to me:

G:\Games\Files here\Txt_ENG\Games\Files here\current\csv

Code:

param(
  $FileName = '*.csv', # File-name filter
  $SourceDir = $PWD,   # Input-files dir.
  $OutDir = $PWD,      # Output-files dir.
  $ColumnIndex = 3,    # 1-based index of the col. of interest
  $OutFileBaseNameSuffix = "_column$ColumnIndex"
)

# Define the destination folder
$destinationFolder = Join-Path -Path $OutDir -ChildPath "Txt_ENG"

# Create the destination folder if it doesn't exist already
if (-not (Test-Path -Path $destinationFolder)) {
    New-Item -Path $destinationFolder -ItemType Directory | Out-Null
}

foreach ($csvFile in Get-ChildItem -LiteralPath $SourceDir -Recurse -Filter $FileName -File) {

  # Import all rows from the current file
  $rows = Import-Csv $csvFile.FullName
  # Determine the name of the column of interest with the specified index.
  # Subtract -1 from $ColumnIndex since array indices start from *0*.
  $colName = ($rows[0].psobject.Properties.Name)[$ColumnIndex-1]

  # Construct the destination path while maintaining the subfolder structure
  $relativePath = $csvFile.FullName.Substring($SourceDir.Length + 1)
  $destinationPath = Join-Path -Path $destinationFolder -ChildPath $relativePath

  # Create the destination folder if it doesn't exist already
  $destinationDirectory = Split-Path -Path $destinationPath -Parent
  if (-not (Test-Path -Path $destinationDirectory)) {
      New-Item -Path $destinationDirectory -ItemType Directory | Out-Null
  }

  # Determine the output file path and name
  $outFile = Join-Path $destinationDirectory ('{0}.txt' -f $csvFile.BaseName)

  # Write the entire file, as UTF-8 without BOM
  $null =
  Set-Content -Path $outFile -Value (
    $colName + "`n" + ($rows.$colName -join "`n") + "`n"
  ) -Encoding UTF8
}

Solution

  • $SourceDir.Length is wrong, $PWD is an object of type PathInfo not a string. Its .Length will be 1, so:

    # using C:\ instead of G:\ to avoid error
    $destination = 'C:\Games\Files here\Txt_ENG'
    $filePath = 'C:\Games\Files here\current\csv\abc.csv'
    Join-Path $destination $filePath.Substring(1 + 1)
    
    # Outputs the unexpected path:
    # C:\Games\Files here\Txt_ENG\Games\Files here\current\csv\abc.csv
    

    What you meant to do is $SourceDir.Path.Length + 1 or $SourceDir.ToString().Length + 1:

    $relativePath = $csvFile.FullName.Substring($SourceDir.Path.Length + 1)