Andrew Beaumont Andrew Beaumont - 3 months ago 18
PowerShell Question

Using Variable in Remove-Item returns "A drive with the name '"E' does not exist"

I have been writing a script which searches for specific folders within an "Archive" folder and then zips them. Once the folder is successfully zipped I would like it to be deleted.

However, I am running into an issue where the

Remove-Item
cmdlet is returning the error "A drive with the name '"E' does not exist" when I use the
foreach
command and a variable.

If I run the
Remove-Item
command manually with the variable the issue does not occur.

Please let me know why this is happening and what I can do to stop it from happening.

Here is the code:

# Get list of archive folders
$ArchiveFolders = Get-ChildItem \*\*\* |
?{ $_.PSIsContainer } |
Where-Object{ $_.Name -eq "_Archived"} | select FullName

# For each archive folder check which subfolders exist within it
foreach ($folder in $ArchiveFolders) {
(Get-ChildItem $folder.FullName | ?{ $_.PSIsContainer } | select FullName | ConvertTo-Csv -NoTypeInformation) |
Select-Object -Skip 1 |
Add-Content -Path e:\scripts\subfolders.csv
}

# Get list of Subfolders
$ArchiveSubFolders = Get-Content e:\scripts\subfolders.csv

# Select each Subfolder
foreach ($subfolder in $ArchiveSubFolders){
# Move each subfolder to a 7z Archive with the highest compression rate available
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "7z.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "a -mx=9 -t7z $subfolder.7z $subfolder"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()

# Check Archive was created successfully and then delete the subfolder
if ($p.ExitCode -eq "0") {
Remove-Item -Path $subfolder -Force -Recurse
} else {
Write-Host "$subfolder has not been deleted"
}
}

Answer

PowerShell CSV export/conversion adds double quotes around the fields. Since you read that CSV output via Get-Content the double quotes are preserved on import, so you get paths "E:\foo" instead of E:\foo. This might work for constructing the external command, but it does not work for PowerShell cmdlets, because there is no drive "E: (with a leading double quote). It's usually a bad idea to make quotes part of the value. You're better off leaving the values without qoutes and adding quotes where they're required.

$ArchiveSubFolders = foreach ($folder in $ArchiveFolders) {
  Get-ChildItem $folder.FullName |
    Where-Object { $_.PSIsContainer } |
    Select-Object -Expand FullName
}

With that said, you don't even need most of your code. You can get the subfolders you want by changing your original path expression to \*\*\*\_Archived\* and run a single Get-ChildItem with that. I'd also recommend dropping the System.Diagnostics.Process approach and use the call operator (&) instead.

Get-ChildItem '\*\*\*\_Archived\*' | Where-Object {
  $_.PSIsContainer
} | Select-Object -Expand FullName | ForEach-Object {
  & 7z.exe a -mx=9 -t7z "$_.7z" "$_"
  if ($LastExitCode -eq 0) {
    Remove-Item -Path $_ -Force -Recurse
  } else {
    Write-Host "$subfolder has not been deleted"
  }
}
Comments