I have the below line in my powershell script in windows 7
$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
The problem I get this error The specified path, file name, or both are too long in some of the files.
I looked into it and found some suggestions to add \\?\ before the file path I tried as below and it's not working any advice?
$Base = '\\?\'
$subFolderItems = Get-ChildItem $Base$i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
As you have commented, the path in $i.FullName is in UNC format (\\server\share\restofpath).
In that case, the prefix for long path should be \\?\UNC\ and the first two backslashes of the path itself need to be removed. In your case, it should be:
\\?\UNC\rackstation.mydom.com\main\sub.arch\mydom-customers\John_Marcus-123456
Using this prefix only works with the -LiteralPath parameter of Get-ChildItem.
Try
Get-ChildItem -LiteralPath ('\\?\UNC\' + $i.FullName.Substring(2))
For things like this, I always keep a small helper function handy:
function Add-LongPathPrefix([string] $Path) {
if ([string]::IsNullOrWhiteSpace($Path) -or $Path.StartsWith('\\?\')) { #'# nothing to do here
return $Path
}
if ($Path.StartsWith('\\')) {
# it's a UNC path like \\server\share\restofpath
return '\\?\UNC\' + $Path.Substring(2) #'# --> \\?\UNC\server\share\restofpath
}
else {
# it's a local path like X:\restofpath
return '\\?\' + $Path #'# --> \\?\X:\restofpath
}
}
Use it like this:
Get-ChildItem -LiteralPath (Add-LongPathPrefix $i.FullName)
P.S. For this you need to have Powershell 5.1 or higher
Hope that helps
Related
Currently I have a script that will sort files in a folder (on their lastwritetime), keep the latest file and move the other files to a different folder. This works correctly:
Get-ChildItem "\\networkfolder\RawData\2_ActionData_Prep\CustomerA\" -Recurse -Filter "*.rpt" -File |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"
The problem is that I have several 'customer' folders and I want to execute the code above in each of those folders.
I tried the following:
$CustomerFolders = Get-ChildItem -Path "\\networkfolder\RawData\2_ActionData_Prep\" -Directory -Recurse
foreach ($folder in $CustomerFolders) {Get-ChildItem -Filter "*.rpt" -File | Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"}
When I execute this script, nothing happens. Also no error comes up. Hopefully someone could help me on this.
Santiago Squarzon noticed that a $folder was missing, so I added $folder in loop for Get-Childitem:
$CustomerFolders = Get-ChildItem -Path "\\networkfolder\RawData\2_ActionData_Prep\" -Directory -Recurse
foreach ($folder in $CustomerFolders) {Get-ChildItem $folder -Filter "*.rpt" -File | Sort-Object -Property LastWriteTime -Descending |
Select-Object -Skip 1 |
Move-Item -Force -Destination "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"}
Now I get an error message:
Get-ChildItem : Cannot find path '\networkfolder\CustomerA' because it does not exist.
It somehow misses the part \RawData\2_ActionData_Prep\ in the path, although I defined it in the $CustomerFolders variable?
You could do the process all with pipelines like this:
$base = "\\networkfolder\RawData\2_ActionData_Prep\"
$destination = "\\networkfolder\RawData\_Archive\Archive_DataRetrieved\"
Get-ChildItem -Path $base -Directory -Recurse | ForEach-Object {
$_ | Get-ChildItem -Filter "*.rpt" -File | Sort-Object LastWriteTime -Descending |
Select-Object -Skip 1 | Move-Item -Force -Destination $destination
}
To briefly explain why Get-ChildItem $folder... failed but $folder | Get-ChildItem ... worked, when we do Get-ChildItem $folder, $folder is being passed as argument for the -Path parameter and the parameter type for it is [string[]]. So, in your code when $folder (a DirectoryInfo instance) is passed as argument, it is being converted to a string and, very unfortunately in Windows PowerShell, when we type convert a DirectoryInfo (and a FileInfo too!) object to string what we get as a result is the Directory Name (this is not the case in PowerShell Core, where the string representation of this object becomes the Directory FullName (a.k.a. Absolute Path) so Get-ChildItem thinks it's being fed a relative path and it looking for the folders in your current location.
However when we do $folder | Get-ChildItem ..., $folder gets bound to the -LiteralPath parameter by Property Name on the PSPath ETS property, in other words, the cmdlet receives the object's provider path (you can think of it as the absolute path of the folder) hence why it works fine.
I'm using PowerShell command prompt and I want to set a location to the folder "Folder". The thing is that folder can be everywhere.
I've tried the command Set-Location and Resolve-Path but I don't get it.
I want to do something like that:
$path = Resolve-Path ".*/Folder"
Set-Location $path
Where the .* can be all the parent folder
Any idea?
Would try this:
Get-ChildItem -Path .\ -Name Folder -Recurse -Depth 10
Hope it helps. BR
Edit (see comments):
$array = Get-ChildItem -Path .\ -Name Ping -Recurse -Depth 10
if($array.Count -eq 0){
#stay
}
if($array.Count -eq 1){
Set-Location $array
}
else{
$array | ForEach-Object{Write-Host $_}
}
Requires PowerShell v3 or higher, you can check using $PSVersionTable.*
$path = (Get-ChildItem . -Recurse -Directory | Where-Object { $_.Name -eq "Folder" }).FullName
This will give you all the directories named Folder in current directory and its subdirectories recursively.
The query, however, can return multiple results so if you want to choose the first one use [0]. Also, to cover the case when the query returns no results, enforce returned object to be an array using #( ... ) and check if it exists:
$f = #(Get-ChildItem . -Recurse -Directory | Where-Object { $_.Name -eq "Folder" })[0].FullName
if ( $f ) {
cd $f
}
else {
# Handle the error
}
cd is alias to Set-Location so you can use whichever you prefer. Important thing to remember is to use FullName property as it contains full path to the folder.
* For PowerShell versions lower than v3, use | Where-Object {$_.PSIsContainer -eq $true} instead of -Directory
I have this PowerShell code that compares 2 directories and removes files if the files no longer exist in the source directory.
For example say I have Folder 1 & Folder 2. I want to compare Folder 1 with Folder 2, If a file doesn't exist anymore in Folder 1 it will remove it from Folder 2.
this code works ok but I have a problem where it also picks up file differences on the date/time. I only want it to pick up a difference if the file doesn't exist anymore in Folder 1.
Compare-Object $source $destination -Property Name -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | % {
if(-not $_.FullName.PSIsContainer) {
UPDATE-LOG "File: $($_.FullName) has been removed from source"
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
}
Is there an extra Where-Object {$file1 <> $file2} or something like that.?
I am not sure how you are getting the information for $source and $destination I am assuming you are using Get-ChildItem
What i would do to eliminate the issue with date/time would be to not capture it in these variables. For Example:
$source = Get-ChildItem C:\temp\Folder1 -Recurse | select -ExpandProperty FullName
$destination = Get-ChildItem C:\temp\Folder2 -Recurse | select -ExpandProperty FullName
By doing this you only get the FullName Property for each object that is a child item not the date/time.
You would need to change some of the script after doing this for it to still work.
If I am not getting it wrong, the issue is your code is deleting the file with different time-stamp as compared to source:
Did you try -ExcludeProperty?
$source = Get-ChildItem "E:\New folder" -Recurse | select -ExcludeProperty Date
The following script can serve your purpose
$Item1=Get-ChildItem 'SourcePath'
$Item2=Get-ChildItem 'DestinationPath'
$DifferenceItem=Compare-Object $Item1 $Item2
$ItemToBeDeleted=$DifferenceItem | where {$_.SideIndicator -eq "=>" }
foreach ($item in $ItemToBeDeleted)
{
$FullPath=$item.InputObject.FullName
Remove-Item $FullPath -Force
}
Try something like this
In PowerShell V5:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 -file).Name
gci $yourdir2 -file | where Name -notin $filesnamedir1| remove-item
In old PowerShell:
$yourdir1="c:\temp"
$yourdir2="c:\temp2"
$filesnamedir1=(gci $yourdir1 | where {$_.psiscontainer -eq $false}).Name
gci $yourdir2 | where {$_.psiscontainer -eq $false -and $_.Name -notin $filesnamedir1} | remove-item
If you want to compare files in multiple dir, use the -recurse option for every gci command.
I am trying to handle errors when scanning through folders. Let's say I have something like:
Get-ChildItem $somepath -Directory | ForEach-Object {
if(error occurred due to too long path) {
skip this folder then
} else {
Write-Host $_.BaseName
}
}
When I do this I print the folders in $somepath until one of them is too long and then the loop stops. Even when using SilentlyContinue. I want to print even after reaching a folder that is too long.
If you can install a non-ancient PowerShell version (3.0 or newer), simply prepend the path with \\?\ to overcome the 260-character limit for full path:
Get-ChildItem "\\?\$somepath" | ForEach {
# ............
}
You could try ignoring the files longer 260 characters by using the Where-Object cmdlet.
Get-ChildItem $somepath -Directory -ErrorAction SilentlyContinue `
| Where-Object {$_.length -lt 261} `
| ForEach-Object { Write-Host $_.BaseName }
Or you could use the following (Ref).
cmd /c dir $somepath /s /b | Where-Object {$_.length -lt 261}
I will add my solution since the neither on this page worked for me. I am using relative paths, so I can't use the \\ prefix.
$TestFiles = Get-ChildItem $pwd "*Tests.dll" -Recurse | Where-Object {$_.FullName.length -lt 261} | Select-Object FullName -ExpandProperty FullName | Where-Object FullName -like "*bin\Release*"
Write-Host "Found TestFiles:"
foreach ($TestFile in $TestFiles) {
Write-Host " $TestFile"
}
I have a directory called Videos. Inside this directory, are a bunch of sub directories of various cameras. I have a script that will check each of the various cameras, and delete recordings older than a certain date.
I am having a bit of trouble getting the full directory information for the cameras. I am using the following to get it:
#Get all of the paths for each camera
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object FullName
And then I loop through each path in $paths and delete whatever I need to:
foreach ($pa in $paths) {
# Delete files older than the $limit.
$file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
$file | Remove-Item -Recurse -Force
$file | Select -Expand FullName | Out-File $logFile -append
}
When I run the script, I am getting errors such as:
#{FullName=C:\Videos\PC1-CAM1}
Get-ChildItem : Cannot find drive. A drive with the name '#{FullName=C' does not exist.
At C:\scripts\BodyCamDelete.ps1:34 char:13
+ $file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsCont ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{FullName=C:String) [Get-ChildItem], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way to strip that #{FullName= off of the Path? I think that may be what the issue is.
In your case $pa is an object with a FullName property. The way you would access that would be this.
$file = Get-ChildItem -Path $pa.FullName -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
However it would just be simpler to change only this line and leave
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
-ExpandProperty will just return the string instead of the object that Select-Object was returning.
You are nearly there. What you want is the -ExpandProperty argument for Select-Object. This will return the value of that property, instead of a FileInfo object with one property, that property being FullName. This should resolve it for you:
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
Edit: Looks like Matt beat me to it by a minute.