I have a script where I recursively delete some bunch of files within certain directory. The problem is in specification of that directory.
When I try to specify it explicitly (i.e. to clear only user1 dir) it works fine:
$temp = "C:\Users\user1\AppData\Local\Temp\"
Get-ChildItem $temp -Recurse -Force -Verbose -ErrorAction SilentlyContinue | remove-item -force -Verbose -recurse -ErrorVariable FailedItems -ErrorAction SilentlyContinue
However when I specify it with wildcard (i.e. to affect all users on this PC)
$temp = "C:\Users\*\AppData\Local\Temp\*"
Get-ChildItem $temp -Recurse -Force -Verbose -ErrorAction SilentlyContinue | remove-item -force -Verbose -recurse -ErrorVariable FailedItems -ErrorAction SilentlyContinue
It fails with the error
Get-ChildItem : Access is denied
At line:7 char:1
+ Get-ChildItem $localTempDir -Recurse -Force -Verbose -ErrorAction Sil ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetChildItemCommand
How that could be?
It is definitely not the permissions issue, 'cause it's the same dir.
And yes, I run script with an elevated privileges.
Other dirs specified in such format, e.g.
C:\Users\*\AppData\Local\Microsoft\Windows\Caches
C:\Windows\Temp\*
are purged like a charm.
Maybe you could use something along these lines, if you want to rule out a list of profiles, and process a list of subfolders:
$targets = "AppData\Local\Microsoft\Windows\Caches",
"AppData\Local\Microsoft\Windows\Temporary Internet Files"
$special = #("Default", "Public")
$profiles = Get-ChildItem "C:\Users" -Directory |
Where-Object Name -NotIn $special |
Select-Object -ExpandProperty FullName
$profiles | ForEach-Object {
foreach($target in $targets) {
$path = Join-Path $_ $target
#delete/empty $path
}
}
NB: syntax is PS3.0+
Related
I am working on small script to capture file hashes on a running system. I only have Powershell available.
This is the active part of the code:
get-childitem -path $path -filter $filename -Recurse -Force | Select FullName | foreach-object { get-filehash $_.fullname | select * }
this is the command I am testing with:
./Get-FileHashesRecursive.ps1 -path c:\ -filename *.txt
When running the script I get a series of errors because certain folders are inaccessible. I'd like to record the paths of those folders so the user has a record on completion of what failed.
the error looks like this in a console window:
get-childitem : Access to the path 'C:\$Recycle.Bin\S-1-5-21-4167544967-4010527683-3770225279-9182' is denied.
At E:\git\Get-RemoteFileHashesRecursive\Get-FileHashesRecursive.ps1:14 char:9
+ get-childitem -path $path -filter $filename -Recurse -Force | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\$Recycle.Bin...3770225279-9182:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way I can grab the path or the entire first line of the error WITHOUT stopping the rest of the script from running?
As requested, here's my earlier comments as an answer:
Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue | ForEach-Object { Get-FileHash -Path $_.FullName | Select-Object * }
$FailedItems | Foreach-Object {$_.CategoryInfo.TargetName} | Out-File "C:\Users\sailingbikeruk\Desktop\noaccess.log"
I have added the -File parameter to Get-ChildItem, because you are specifically dealing with only files.
I also added the -ErrorVariable and -ErrorAction parameters to the Get-ChildItem command. -ErrorVariable FailedItems defines a custom name for a variable which stores errors from the command during processing. -ErrorAction SilentlyContinue, tells the script to continue without notifying you of the errors.
Once your command has finished processing, you can parse the content of the $FailedItems variable. In the example above, I've output the TargetName to a file so that you can read it at your leisure, (please remember to adjust its file path and name as needed, should you also wish to output it to a file).
The history of this question lies in an earlier question I asked here
I am running this command to get the file hashes of all files in a given location, but I need to capture any that are missed or inaccessible.
Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue | ForEach-Object { Get-FileHash -Path $_.FullName | Select-Object * }
$FailedItems | Foreach-Object {$_.CategoryInfo.TargetName} | Out-File "C:\Users\sailingbikeruk\Desktop\noaccess.log"
In the earlier question I thought that I just needed to catch folders, and the answer given and accepted did capture any folder access denied messages but the command doesn't capture individual files that are inaccessible. The suggested answer (using -errorvariable) doesn't appear to record the path of these.
I am not clear as to why the -ErrorVariable is catching the paths from this error:
get-childitem : Access to the path 'C:\$Recycle.Bin\S-1-5-21-4167544967-4010527683-3770225279-9182' is denied.
At E:\git\Get-RemoteFileHashesRecursive\Get-FileHashesRecursive.ps1:14 char:9
+ get-childitem -path $path -filter $filename -Recurse -Force | ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\$Recycle.Bin...3770225279-9182:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
but not this one
Get-FileHash : The file 'E:\devices.csv' cannot be read: The process cannot access the file
'E:\devices.csv' because it is being used by another process.
At E:\Scripts\Ian\git\Get-RemoteFileHashesRecursive\Get-FileHashesRecursive.ps1:25 char:132
+ ... FailedItems | ForEach-Object { Get-FileHash -Path $_.FullName | Selec ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (E:\devices.csv:PSObject) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : FileReadError,Get-FileHash
In this example I am writing $_.CategoryInfo.TargetName to the error log, but I have also tried writing $_.TargetObject and get the same results
The common parameters -ErrorVariable and -ErrorAction apply to a single command only. So you have to add them to Get-FileHash too:
Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue |
ForEach-Object {
Get-FileHash -Path $_.FullName -ErrorVariable +FailedItems -ErrorAction SilentlyContinue | Select-Object *
}
$FailedItems | Foreach-Object {$_.CategoryInfo.TargetName} | Out-File "C:\Users\sailingbikeruk\Desktop\noaccess.log"
Note that I have inserted + in front of the error variable name for Get-FileHash to prevent it from clearing any errors produced by Get-ChildItem. See about_CommonParameters.
Unrelated improvements:
You can remove ForEach-Object and just pipe Get-ChildItem directly into Get-FileHash. Also Select-Object * is superfluous.
Get-ChildItem -Path $Path -Filter $Filename -File -Recurse -Force -ErrorVariable FailedItems -ErrorAction SilentlyContinue |
Get-FileHash -ErrorVariable +FailedItems -ErrorAction SilentlyContinue
I am using a one liner to find a registry key based on a value then delete it's parent. The one liner produces an error but if I separate the search result into a variable and run remove-item there is no error. I'd like to find out what causes this and if I should I be worried?
Produces an error:
Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath | Remove-Item -Recurse -confirm
Get-ChildItem : The registry key at the specified path does not exist.
At line:1 char:1
+ Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurs ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (HKEY_LOCAL_MACH...4D34\SourceList:String) [Get-ChildItem],
ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.GetChildItemCommand
Produces No Errors:
$offending_key= Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath
Remove-Item -Recurse $offending_key -confirm
That's because it is iterating recursively through the registry tree, and you deleted part of that tree in the middle of the iteration. You could put parenthesis around everything but the last part, so that it finishes iteration first, or you could put the last part in a ForEach-Object loop, and add a break after it so once that key is found it removes it and stops looking.
Complete Get-ChildItem iteration before deleting:
(Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath) | Remove-Item -Recurse -confirm
Stop after finding the first matching key:
Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath | ForEach-Object {$_ | Remove-Item -Recurse -confirm; break}
I have created a script to copy a local file on remote server
Remote location is C:\past and local file needs to copy in all sub-directories from c:\past.
(i.e. c:\past\1, c:\past\2, c:\past3, c:\past\4 etc. etc..)
$PathFrom = "C:\ISO\ncis.exe"
$computers="192.168.42.117"
foreach ($computer in $computers)
{
$folders = Get-ChildItem "C:\past" -Directory
}
foreach ($folder in $folders.name)
{
#copy-item _path $PathFrom -ToSession $TargetSession -Destination "C:\past\$folder" -Recurse -ComputerName $computers
copy-item _path $PathFrom -ComputerName $computers -Destination "C:\past\$folder" -Recurse
}
Getting below error
enter Get-ChildItem : Cannot find path 'C:\past' because it does not
exist.
At line:3 char:14
+ $folders = Get-ChildItem "C:\past" -Directory
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\past:String) [Get-
ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId :
PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommandcode
here
Since you said you can get to it througn a UNC path this should do what your looking for...
$PathFrom = "C:\ISO\ncis.exe"
$computers="192.168.42.117"
foreach ($computer in $computers){
Get-ChildItem "\\$computer\C$\past" -Directory | %{ Copy-Item -path $PathFrom -Destination $_.Fullname }
}
foreach ($folder in $folders.fullname)
Use Fullname instead of name.
This doesn't make sense, it is getting directory from local machine.
foreach ($computer in $computers)
{
$folders = Get-ChildItem "C:\past" -Directory
}
Copy-Item doesn't have -ComputerName Parameter
copy-item _path $PathFrom -ComputerName $computers
Check Examples
Microsoft Copy-Item
Using PowerShell 4.0,
I am trying to get the size of multiple directories and I am getting very inconsistent results between what windows tells me and what my code is telling me.
The code in question is:
$temp4 = ($folderInfo.rootFolder).fullname
$folderInfo.directories += Get-ChildItem -LiteralPath $temp4 -Recurse -Force -Directory
$folderInfo.directories += $folderInfo.rootFolder
foreach ($dir in $folderInfo.directories)
{
$temp3 = $dir.fullname
$temp2 = Get-ChildItem -LiteralPath $temp3 -Force
$temp = (Get-ChildItem -LiteralPath $dir.fullname -Force -File | Measure-Object -Property length -Sum -ErrorAction SilentlyContinue).Sum
$folderInfo.totalSize += $temp
}
return $folderInfo
if $folderInfo.rootFolder = D:\sample
then I get what I want
but if $folderInfo.rootFolder = D:\[sample
then I get
Get-ChildItem : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: sample [sample
At C:\powershell scripts\test.ps1:55 char:12
+ $temp = (Get-ChildItem $dir.fullname -Force -File | Measure-Object -Property l ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.GetChildItemCommand
The same holds true if D:\sample contains a folder somewhere in it's children that is "[sample". I will get correct results from everything else, but anything in or beyond the problem directory. Both $dir.pspath and $dir.fullname screw things up.
Edit: changed the above code to reflect it's current state and included the full error.
edit again: The code above now has some debugging temp variables.
Use the -LiteralPath parameter in place of -Path to suppress the wildcard globbing. Also, since you're using V4, you can use the -Directory switch and dispense with the $_.iscontainer filter:
$folderInfo.directories =
Get-ChildItem -LiteralPath $folderInfo.rootFolder -Recurse -Force -Directory
If you have more squre brackets farther down the directory tree, keep using literpath in subsequent Get-ChildItem commands:
$folderInfo.directories += Get-ChildItem -LiteralPath $folderInfo.rootFolder -Recurse -Force -Directory
$folderInfo.directories += Get-Item -LiteralPath $folderInfo.rootFolder
foreach ($dir in $folderInfo.directories)
{
$temp2 = Get-ChildItem -LiteralPath $dir.PSPath -Force
$temp = (Get-ChildItem -LiteralPath $dir.fullname -Force -File | Measure-Object -Property length -Sum -ErrorAction SilentlyContinue).Sum
$folderInfo.totalSize += $temp
}
return $folderInfo