Script to cleanup old backup files permission denied

I am getting an error trying to automatically remove old vhd files. These are owned by the system account and I have tried multiple ways to take ownership. This is what I have so far:

#Remove the old backups
$limit = (Get-Date).AddDays(-10)
$path = "\\backup\sbs01_backup\"

# Delete files older than the $limit.
$files = Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit }
Foreach ($file in $files) {
     $objUser = [Environment]::UserName
     $objFile = Get-Acl
     $objFile = $objFile.SetOwner($objUser)
     Set-Acl -aclobject $objFile -path $file.FullName
     }
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
# Delete any empty directories left behind after deleting the old files.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse

This is the error:

Cannot convert argument "0", with value: "Administrator", for "SetOwner" to type "System.Security.Principal.IdentityReference": "Cannot convert the "Administrator" value of type "System.String" to type "System.Security.Principal.IdentityReference"." At C:\BackupScripts\Cleanup.ps1:11 char:34 + $objFile = $objFile.SetOwner <<<< ($objUser) + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Set-Acl : Attempted to perform an unauthorized operation.
At C:\BackupScripts\Cleanup.ps1:12 char:13

  •  Set-Acl &lt;&lt;&lt;&lt;  -aclobject $objFile -path $file.FullName
    
    • CategoryInfo : PermissionDenied: (\backup\sbs01_…06e6f6e6963.vhd:String) [Set-Acl], UnauthorizedAccessException
    • FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetAclCommand

I’ve tried entering the username as domain\administrator, but that fails as well. There must be a better way to remove the files, it does work interactively and I can delete the files with explorer. The remote share is on a Buffalo NAS with no access restrictions set.

Welcome to .NET. Ugh.

According to that error, it doesn’t want a username at all. It wants an object of the type System.Security.Principal.IdentityReference (http://msdn.microsoft.com/en-us/library/system.security.principal.identityreference(v=vs.110).aspx), and you’re giving it a string, which is ticking it off. That’s actually a base class, you probably want a System.Security.Principal.NTAccount.

$account = New-Object -Type System.Security.Principal.NTAccount -Arg “DOMAIN”,“User”

I’m guessing. Based on http://msdn.microsoft.com/en-us/library/system.security.principal.ntaccount(v=vs.110).aspx.

You could also just use CACLS from your script.

I tried subinacl but was having a tough time passing the objects in the loop as the path parameter. It also didn’t like the /subdirectories being used with a UNC path. I’ll look into the CACLS option. Why does the script fail to delete the object when I can delete it from the command line interactively? Maybe I don’t need to set permissions. What is the difference in how windows applies the permissions in script vs interactively? Or is it the object that is different? Is there a better way to enumerate the objects that will pass them to remove-item and work?

Well, I don’t know what you’re doing interactively at the command line. There’s a lot of ways a given tool can work; the Cmd.exe “Del” command uses some fairly low-level OS APIs. The PowerShell “Remove-Item” goes through .NET. So the behavior between the two isn’t going to be identical.

There isn’t necessarily a difference in “how Windows applies permissions in script vs interactively.” What’s different are the tools you’re using. In PowerShell, you’re nearly always going through the .NET Framework unless using an external executable (like Cacls.exe). When you use the Explorer dialog box, there’s entirely different code running. It isn’t like Explorer is just running PowerShell under the hood ;). So the differences between a PowerShell command and the GUI dialog are probably massive. It isn’t like there’s one single “delete a file” mechanism in Windows that everything just calls into - unfortunately.

It isn’t how you’re enumerating the objects, either.

Think of it this way: I told you that, interactively riding a bike, I was able to get to the store. But when I got in my car, I couldn’t get there. Massively different mechanisms to accomplish the same task. Maybe my car was out of gas. Maybe my garage door was closed. There’s an entirely different thing happening with one mechanism vs the other.

Thank you for the explanation, let me clarify.

Remove-item works from the shell.
PS C:&gt; remove-item ‘\backup\SBS01_backup\Friday20131129\d\WindowsImageBackup\server\Backup 2013-11-30 002622\2d398a8b-7954-11de-9c9a-806e6f6e6963.vhd’
PS C:&gt;

But the script gets this error

PS C:\Users\wgtadmin> C:\BackupScripts\Cleanup.ps1
Remove-Item : Cannot remove item \backup\sbs01_backup\Friday20131129\c\WindowsImageBackup\server\Backup 2013-11-30 000002\2d398a8a-7954-11de-9c9a-806e6f6e6963.vhd: Access to the path is denied.
At C:\BackupScripts\Cleanup.ps1:14 char:125

  • Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$.PSIsContainer -and $.CreationTime -lt $limit } | Remove-Item <<<< -Force
    • CategoryInfo : InvalidArgument: (\backup\sbs01_…06e6f6e6963.vhd:FileInfo) [Remove-Item], ArgumentException
    • FullyQualifiedErrorId : RemoveFileSystemItemArgumentError,Microsoft.PowerShell.Commands.RemoveItemCommand
      Remove-Item : Cannot remove item \backup\sbs01_backup\Saturday20131130\c\WindowsImageBackup\server\Backup 2013-12-01 000002\2d398a8a-7954-11de-9c9a-806e6f6e6963.vhd: Access to the path is denied.

      So I was wondering if I would be able to use remove-item in a different way in the script would it work?

You know those are two different paths, right? I’m not sure if that was supposed to be the case or not. One is point in to “D” and the other to “C.” The error you’re getting isn’t about file ownership, I don’t think. That’s “Access Denied,” not “Access to the Path Denied.” What you’re getting suggests that the path is inaccessible.

Yes the script wouldn’t get the “d” path after I had deleted the file. That’s what I’m stuck on, I suspected ownership of the vhd file.

PSMessageDetails : Exception : System.IO.DirectoryNotFoundException: Could not find a part of the path '\\backup\sbs01_backup\Sunday20131201\c\WindowsImageBackup\server\Catalog'. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.Directory.InternalGetFileDirectoryNames(String path, String userPathOriginal, String searchPattern, Boolean includeFiles, Boolean includeDirs, SearchOpti on searchOption) at System.IO.DirectoryInfo.GetDirectories(String searchPattern, SearchOption searchOption) at Microsoft.PowerShell.Commands.FileSystemProvider.Dir(DirectoryInfo directory, Boolean recurse, Boolean nameOnly, ReturnContainers returnContainers) TargetObject : \\backup\sbs01_backup\Sunday20131201\c\WindowsImageBackup\server\Catalog CategoryInfo : ReadError: (\\backup\sbs01_...C-SBS01\Catalog:String) [Get-ChildItem], DirectoryNotFoundException FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand ErrorDetails : InvocationInfo : System.Management.Automation.InvocationInfo PipelineIterationInfo : {0, 1, 26, 1}

Looks like it might just be a space. Backup Exec is getting put in soon :slight_smile: I’m using this challenge to practice PowerShell so I really do appreciate the help.

No, this error shows full path.


PSMessageDetails      : 
Exception             : System.ArgumentException: Access to the path is denied.
                           at System.IO.FileSystemInfo.set_Attributes(FileAttributes value)
                           at Microsoft.PowerShell.Commands.FileSystemProvider.RemoveFileSystemItem(FileSystemInfo fileSystemInfo, Boolean force)
TargetObject          : \\backup\sbs01_backup\Sunday20131201\c\WindowsImageBackup\server\Backup 2013-12-02 000002\2d398a8a-7954-11de-9c9a-806e6f6e6963.vhd
CategoryInfo          : InvalidArgument: (\\backup\sbs01_...06e6f6e6963.vhd:FileInfo) [Remove-Item], ArgumentException
FullyQualifiedErrorId : RemoveFileSystemItemArgumentError,Microsoft.PowerShell.Commands.RemoveItemCommand
ErrorDetails          : Cannot remove item \\backup\sbs01_backup\Sunday20131201\c\WindowsImageBackup\server\Backup 2013-12-02 000002\2d398a8a-7954-11de-9c9a-806e6f6e6963.vhd: Access to the 
                        path is denied.
InvocationInfo        : System.Management.Automation.InvocationInfo
PipelineIterationInfo : {0, 1, 26, 3}

So a mapped drive? That didn’t work either.

Yeah, don’t know what to tell you but this isn’t a permissions issue, I don’t think. I mean, if Remove-Item deletes it manually, then Remove-Item should work the same from a script. No difference. It’s something in the value the script is working with.

So you try to access each successive piece of the path, one at a time, to see when it fails. Can you delete a file from \backup\sbs01_backup? Just make a little text file, and try to delete it from within a script.

In your existing script, can you - again, as a test - paste a manually typed, hardcoded path? Does it work then? Maybe copy-and-paste the path from a console session that WORKS, so you KNOW you’ve got a valid path.

Tests like that help tell us what’s going wrong.