Powershell Invoke-Expression stopped at command

by wkiess01 at 2012-09-06 19:56:55

Hi Powershell Gurus!

I’m new to Powershell and loving it. So much more control and power than the old DOS batch files…

I’m writing a Powershell script to copy a (large >100GB) folder from our file server to a USB drive as a disaster recovery facility. Before I can copy the large folder, I check if sufficient space is available on the USB drive,. If not, I locate and delete the oldest copy of the folder. At least I want to delete it.

I’ve managed to get to the point of knowing the folder path to remove, but when I invoke the expression to do so, Powershell stops with the message:

[DBG]>>> Stopped at: cmd /c "rd f:\Backups\20120815 /s"

It won’t step or run any further. Can anyone shed any light onto why this is happening and how I can overcome this problem?

Here is the full script (cobbled together from various website’s suggestions and my own discoveries):

try
{
# Find the external target USB Drive
$x = get-WmiObject -Class win32_logicaldisk | select -Property deviceid, volumename | findstr USB_FileArchive
}
catch
{
echo "Caught: Unable to locate External USB Drive for Files Backup." >> c:\temp\BackupFiles.log
exit /b
}
if ($x) {}
else
{
echo "Null: Unable to locate External USB Drive for Files Backup." >> c:\temp\BackupFiles.log
exit /b
}

# Extract the drive letter of the target drive
$x = $x.Substring(0,2)

# Determine Source Folder size so we can work out if there’s enough room on the target
$objFSO = New-Object -com Scripting.FileSystemObject
$srcSize = "{0:N2}" -f (($objFSO.GetFolder("d:\company").Size) / 1GB)

# Determine free space on target drive
$f=get-wmiobject win32_logicaldisk -filter "drivetype=3" | select-object deviceid, freespace,size | findstr $x | %{ $.Split(" ",[StringSplitOptions]"RemoveEmptyEntries")[1] }
$freeSpace="{0:N2}" -f ($f / 1GB)

# Check available space
$availSpace = $freeSpace - $srcSize
if ($availSpace -lt 0)
{
# Find oldest folder and remove it
$oldestFolder = dir f:\backups | ?{$
.psiscontainer} | sort creationtime | select -first 1 | select name

$cmd = ‘cmd /c "rd ’ + ("f:\Backups" + $oldestFolder.Name) + ’ /s"’
try
{
invoke-expression -command $cmd
}
catch
{
write-host "Error"
}
}

# Now that there is enough space,
# Copy the backup files
#Robocopy.exe "D:\Company" $x\Backups /MIR /NP /FP /PURGE 2>&1 >> c:\temp\BackupFiles.log


Cheers,
Walter
by coderaven at 2012-09-06 20:40:26
Most of the actions in your script are still DOS commands. And that is the beauty of PowerShell, you can mix and match as you need to get the job done as you learn.

Since the rest of your script is working at this moment, concerning that line – invoke-expression -command $cmd – here is what I recommend

The problem is with this line – $cmd = ‘cmd /c "rd ’ + ("f:\Backups" + $oldestFolder.Name) + ’ /s"’ ! Change that line to this:
$cmd = "cmd /c "rd f:\Backups\$($oldestFolder.Name) /s""
The backtick that is on the key with the ~ next to the 1 key will allow you to escape characters that are reserved in PowerShell. Here we are escaping the " inside the string so they are not confused to be terminators. Also we make the enclosing quotes " so that the internal variables are still processed. With the variable in the string pulling a property if you enclose it in $( ) to have it process correctly. This is a very common early mistake and can be confusing so don’t sweat it,

Sorry for the quick wordy response. Let me know if this helps.
for more info from inside PowerShell run:
Get-Help about_Quoting_Rules
or
Get-Help about_Escape_Characters
by wkiess01 at 2012-09-06 20:57:38
Hi Allen,

Thanks for your "quick wordy" response. Just what I need to learn more… :slight_smile:

I tried it and came up with the same result…see below:

[DBG]>>> Hit Line breakpoint on ‘C:\Users\sapsadm\BackupFiles.ps1:53’
[DBG]: PS C:\Users\sapsadm>>> $cmd
cmd /c "rd f:\Backups\20120815 /s"

________________________________________________________________________________________________________________________
[DBG]>>> Stopped at: cmd /c "rd f:\Backups\20120815 /s"

I note that the resultant command stored in $cmd works out to be the same as what I had originally. BTW, I’m stepping thru the script using F11 after a break point on the invoke-expression line.

So it’s back to the drawing board. If the command is being issued correctly, does that perhaps mean that there is a windows/powershell setting that I am missing rather than a programming error? Or is it just taking a LONG time due to the folder being over 100GB in size?

Cheers,
Walter
by wkiess01 at 2012-09-06 22:37:33
OK, So I’ve had a bit of a look around and have come up with another Powershell command to remove the oldest folder:

Remove-Item -Recurse -Force $oldestFolder.Name

When I step into this command I get the following message in the Poweshell ISE:

[DBG]>>> Stopped at: if ($
.FullyQualifiedErrorId -ne "NativeCommandErrorMessage" -and $ErrorView -ne "CategoryView") {

Huh? That’s not my code! What am I missing here? Why can’t I remove this folder?

Cheers,
Walter
by coderaven at 2012-09-07 04:38:32
I like that you moved to the Remove-Item command. That will give you better results

Try changing the $oldestFolder.Name to $oldestFolder.FullName because the FullName will pass the entire path not just the short name of that folder.

Also, before you actually run your Remove-Item command, try just making sure your variable is correct. Just put $oldestFolder.FullName and it will output to the shell and comment out the Remove-Item. Once you know you are getting a valid bit of data, uncomment your Remove-Item and remove the extra line of testing code.