Powershell Error Message - Object Not Found [duplicate] - powershell

I wrote a powershell script to strip R/H/S attributes off all files in a specified set of root paths. The relevant code is:
$Mask = [System.IO.FileAttributes]::ReadOnly.Value__ -bor [System.IO.FileAttributes]::Hidden.Value__ -bor [System.IO.FileAttributes]::System.Value__
Get-ChildItem -Path $Paths -Force -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$Value = $_.Attributes.value__
if($Value -band $Mask) {
$Value = $Value -band -bnot $Mask
if($PSCmdlet.ShouldProcess($_.FullName, "Set $([System.IO.FileAttributes] $Value)")) {
$_.Attributes = $Value
}
}
}
This works fine, but when processing one very large folder structure, I got a few errors like this:
Exception setting "Attributes": "Could not find a part of the path 'XXXXXXXXXX'."
At YYYYYYYYYY\Grant-FullAccess.ps1:77 char:17
+ $_.Attributes = $Value
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
I find this strange because the FileInfo object being manipulated is guaranteed to exist, since it comes from a file search.
I can't give the file names because they are confidential, but I can say:
they are 113-116 characters long
the unique set of characters involved are %()+-.0123456789ABCDEFGIKLNOPRSTUVWX, none of which are illegal in a file name
the % character is there due to URL-encoded spaces (%20)
Do you have any suggestions as to what may be causing this? I assume that if the full path was too long, or I didn't have write permissions to the file, then a more appropriate error would be thrown.

As stated in your own answer, the problem turned out to be an overly long path (longer than the legacy limit of 259 chars.)
In addition to enabling long-path support via Group Policy, you can enable it on a per-computer basis via the registry as follows, which requires running with elevation (as admin):
# NOTE: Must be run elevated (as admin).
# Change will take effect in FUTURE sessions.
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled 1
Pass 0 to turn support off.
However, even with long-path supported turned OFF (as is invariably the case on pre-Windows 10 versions) it is possible to handle long paths:
In Windows PowerShell (PowerShell up to version 5.1), you must use the long-path opt-in prefix, \\?\, as discussed below.
In PowerShell [Core] v6+, no extra work is needed, because it always supports long paths - you neither need to turn on support system-wide nor do you need the long-path prefix discussed below.
Caveat: While you may use \\?\ in PowerShell [Core] as well in principle, support for it is inconsistent as of v7.0.0-rc.2; see GitHub issue #10805.
Important: Prefix \\?\ only works under the following conditions:
The prefixed path must be a full (absolute), normalized path (must not contain . or .. components).
E.g., \\?\C:\path\to\foo.txt works, but \\?\.\foo.txt does not.
Furthermore, if the path is a UNC path, the path requires a different form:
\\?\UNC\<server>\<share>\...;
E.g., \\server1\share2 must be represented as \\?\UNC\server1\share2

It did turn out to be a long path issue after all, despite the wording of the error messages. A simple Get-ChildItem search for the files produced the same errors. I finally tracked down the files mentioned in the error messages and measured their total path lengths. They were exceeding 260 characters.
I experimented with adding a \\?\ prefix to the paths, but powershell doesn't seem to like that syntax.
Fortunately, the script is being used on Windows 2016, so I tried enabling long path support in group policy. That made the whole problem go away.

Related

I am trying to create a shortcut in Powershell from one server to another

$PrivateDrive = "Sharedrivepath1"
$ScanDrive = "ScanDrivePath2"
New-Item -Itemtype SymbolicLink -Path $PrivateDrive -Name ScanDrive -Value $ScanDrive
I am trying to create a shortcut from the ScanDrive to the PrivateDrive, I have a full filepath and have access to both locations.
These both exist.
But I get the error "New-Item : Symbolic Links are not supported for the specified path"
EDIT: This is how I declare my Private and Scan Drives
$SamaccountName = ($name).Givenname + '.' + ($name.Surname)
$PrivateDrive = '\\SERVER1\private\home folders\' + $SamaccountName
$ScanDrive = "\\SERVER2\Shares_2\" + $SamaccountName
The error message is PowerShell's, in response to the underlying CreateSymbolicLink() WinAPI function reporting error code 1 (INVALID_FUNCTION).
There are two possible causes that I'm aware of:
A configuration problem: R2R (Remote-to-Remote) symlink evaluation is disabled (which is true by default.
To query the current configuration, run the following:
fsutil behavior get SymLinkEvaluation
To modify the configuration, you must call from an elevated (run as admin) session. The following enables R2R symlink evaluation:
# Requires an ELEVATED session.
fsutil behavior set SymLinkEvaluation R2R:1
(Less likely) A fundamental limitation:
The remote link path (the target path too?) is not exposed vie one of the following technologies, which are the ones listed as supported in the linked WinAPI help topic:
Server Message Block (SMB) 3.0 protocol
SMB 3.0 Transparent Failover (TFO)
Resilient File System (ReFS)

"$env:userprofile" does not yield the same result as using "%userprofile%" in file explorer

I'm attempting to find a users downloads directory in powershell using this line:
$downloadDirectory = "$env:USERPROFILE\Downloads"
But I'm getting the following error:
Get-ChildItem : Cannot find path 'C:\Users\skewb\Downloads' because it does not exist.
At D:\Users\Skewb\Documents\repos\DotaMatchFinder\unzip_move_run.ps1:16 char:5
+ Get-ChildItem -Path $downloadDirectory
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\skewb\Downloads:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
When I type the following into the file explorer %USERPROFILE%/Downloads
I'm taken to the correct path D:\Users\Skewb\Downloads
Is this intended? Do I need to find this directory another way?
Your symptom is mysterious (see bottom section), but can - probably - be bypassed with a solution that is conceptually preferable anyway:
Since, as zett42 points out, the so-called known or special folders (folders known to the system to have specific purposes) may be redirected to a location other than their default location, the robust solution is to ask the system for that location, via a symbolic name.
Unfortunately, that isn't quite as straightforward as one would hope:
$downloadDirectory =
(New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path
A third-party list of supported symbolic names can be found here; the official conceptual help topic about known folders is not shell-friendly, unfortunately.
As of PowerShell 7.1, there is no PowerShell-native way to query known folders, but there's pending GitHub proposal #6966 to change that.
While .NET does have an API, [System.Environment]::GetFolderPath($symbolicName), its set of special folders is incomplete, and notably doesn't include the Downloads folder.
(New-Object -ComObject WScript.Shell).SpecialFolders($symbolicName) is similarly incomplete with respect to the supported set of special folders.
Caveat: While it is tempting to try to get known-folder information from the registry, this is officially advised against - see this blog post by Raymond Chen.
As for your symptom:
My guess is that something in your PowerShell profile(s) accidentally redefines the USERPROFILE environment, which, while technically possible, is obviously ill-advised.

How to move file on remote server to another location on the same remote server using PowerShell

Currently, I run the following command to fetch the files to my local system.
Get-SCPFile
-ComputerName $server
-Credential $credential
-RemoteFile ($origin + $target + ".csv")
-LocalFile ($destination + $target + ".csv")
It works as I'd like (although it sucks that I can't copy multiple files by regex and/or wildcard). However, after the operation has been carried out, I'd like to move the remote files to another directory on the remote server so instead of residing in $origin at $server, I want them to be placed in $origin + "/done" at the same server. Today, I have to use PuTTY for that but it would be so much more convenient to do that from PS.
Googling gave me a lot of material but I couldn't make it work. At the moment, I'm not sure if I'm specifying the path incorrectly somehow or if it's not possible to use the plain commands when working against an external, secured, Unix-server.
For copying files, I can't use Copy-Item, hence the function Get-SCPFile. I can imagine that remote moving, renaming and listing the items isn't possible neither for the same reason (whatever that reason is).
This example as well as this one produce error cannot find path despite the value being used for copying the file successfully with the script at the top. I'm pretty sure it's a misleading error message (not being enitrely sure, though).
$file = "\\" + $server + "" + $origin + "" + $target + ".csv"
# \\L234231.vds.afm.se/var/trans/ut/drish/sxx/meta001.csv
Remove-Item $file -force
Many answers (like this) are very simple, which supports my theory that the combination of Unix and secure raise an extra challenge. Perhaps I'm wording the question insufficiently well.
There's also more advanced examples, still not working, just hanging up the window with no error messages. I feel my competence prevents me from estimating the degree of screwuppiness in this approach.
In PowerShell you can create a PowerShell Session (PSSession) from your System remotly on another System (and into another Session on your System but thats details... ) and execute your commands there.
You can create a PSSession with New-PSSession but a lot of cmdlets have a-ComputerName parameter (or something similar) so that they can be executed remotley without creating a PSSession first.
A PSSession can be used with Enter-PSSession to get an interactive Session or with Invoke-Command to execute a ScriptBlock. That way you could test your Remove-Item command directly on the target server. Depending on the setup you might need to use Linux syntax within the remote session.
Here are some more infos about_PSSessions and using it with SSH to connect to Linux

Error "Could not find a part of the path" while setting attributes on an existing file

I wrote a powershell script to strip R/H/S attributes off all files in a specified set of root paths. The relevant code is:
$Mask = [System.IO.FileAttributes]::ReadOnly.Value__ -bor [System.IO.FileAttributes]::Hidden.Value__ -bor [System.IO.FileAttributes]::System.Value__
Get-ChildItem -Path $Paths -Force -Recurse -ErrorAction SilentlyContinue | ForEach-Object {
$Value = $_.Attributes.value__
if($Value -band $Mask) {
$Value = $Value -band -bnot $Mask
if($PSCmdlet.ShouldProcess($_.FullName, "Set $([System.IO.FileAttributes] $Value)")) {
$_.Attributes = $Value
}
}
}
This works fine, but when processing one very large folder structure, I got a few errors like this:
Exception setting "Attributes": "Could not find a part of the path 'XXXXXXXXXX'."
At YYYYYYYYYY\Grant-FullAccess.ps1:77 char:17
+ $_.Attributes = $Value
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
I find this strange because the FileInfo object being manipulated is guaranteed to exist, since it comes from a file search.
I can't give the file names because they are confidential, but I can say:
they are 113-116 characters long
the unique set of characters involved are %()+-.0123456789ABCDEFGIKLNOPRSTUVWX, none of which are illegal in a file name
the % character is there due to URL-encoded spaces (%20)
Do you have any suggestions as to what may be causing this? I assume that if the full path was too long, or I didn't have write permissions to the file, then a more appropriate error would be thrown.
As stated in your own answer, the problem turned out to be an overly long path (longer than the legacy limit of 259 chars.)
In addition to enabling long-path support via Group Policy, you can enable it on a per-computer basis via the registry as follows, which requires running with elevation (as admin):
# NOTE: Must be run elevated (as admin).
# Change will take effect in FUTURE sessions.
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem LongPathsEnabled 1
Pass 0 to turn support off.
However, even with long-path supported turned OFF (as is invariably the case on pre-Windows 10 versions) it is possible to handle long paths:
In Windows PowerShell (PowerShell up to version 5.1), you must use the long-path opt-in prefix, \\?\, as discussed below.
In PowerShell [Core] v6+, no extra work is needed, because it always supports long paths - you neither need to turn on support system-wide nor do you need the long-path prefix discussed below.
Caveat: While you may use \\?\ in PowerShell [Core] as well in principle, support for it is inconsistent as of v7.0.0-rc.2; see GitHub issue #10805.
Important: Prefix \\?\ only works under the following conditions:
The prefixed path must be a full (absolute), normalized path (must not contain . or .. components).
E.g., \\?\C:\path\to\foo.txt works, but \\?\.\foo.txt does not.
Furthermore, if the path is a UNC path, the path requires a different form:
\\?\UNC\<server>\<share>\...;
E.g., \\server1\share2 must be represented as \\?\UNC\server1\share2
It did turn out to be a long path issue after all, despite the wording of the error messages. A simple Get-ChildItem search for the files produced the same errors. I finally tracked down the files mentioned in the error messages and measured their total path lengths. They were exceeding 260 characters.
I experimented with adding a \\?\ prefix to the paths, but powershell doesn't seem to like that syntax.
Fortunately, the script is being used on Windows 2016, so I tried enabling long path support in group policy. That made the whole problem go away.

Error in PowerShell due to copying the content of an S3 bucket

I copy the content of an S3 bucket to a local directory, however I get an error output from the powershell.
Copy-S3Object : The requested range is not satisfiable
It is pointing to this command:
Copy-S3Object -BucketName $bucket -Key $object.Key -LocalFile $localFilePath -Region $region
Why do I get this error ? Note that the desired files that are needed to be copied do indeed get copied locally.
I can't say why you are getting that error returned from S3, but I can tell you that if you are copying multiple objects you probably want to use the -LocalFolder parameter, not -LocalFile. -LocalFolder will preserve the prefixes as subpaths.
When downloading one or more objects from S3, the Read-S3Object cmdlet works the same as Copy-S3Object, but uses -KeyPrefix to specify the common prefix the objects share, and -Folder to indicate the folder they should be downloaded to.
This also reminds me I need to check why we used -LocalFolder on Copy-, and -Folder on Read- although I suspect aliases may also be available to make them consistent.
HTH
(Edit): I spent some time this morning reviewing the cmdlet code and it doesn't appear to me the cmdlet would work as-is on a multi-object download, even though it has a -LocalFolder parameter. If you have a single object to download, then using -Key/-LocalFile is the correct parameter combination. If -LocalFolder is passed, the cmdlet sets up internally to do a single file download instead of treating -Key as a common key prefix to a set of objects. So, I think we have a bug here that I'm looking into.
In the meantime, I would use Read-S3Object to do your downloads. It supports both single (-Key) or multi-object download (-KeyPrefix) modes. https://docs.aws.amazon.com/powershell/latest/reference/index.html?page=Read-S3Object.html&tocid=Read-S3Object
this seems to occur with folders that do not contain files since copy wants to copy files.
i accepted this error and trapped it.
catch [Amazon.S3.AmazonS3Exception]
{
# get error record
[Management.Automation.ErrorRecord]$e = $_
# retrieve information about runtime error
$info = [PSCustomObject]#{
Exception = $e.Exception.Message
Reason = $e.CategoryInfo.Reason
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
ErrorCode = $e.Exception.ErrorCode
}
if ($info.ErrorCode="InvalidRange") { #do nothing
} Else {
# output information. Post-process collected info, and log info (optional)
write-host $info -ForegroundColor Red}
}
}
This happened to me when I tried to download the file which had more than one dots in it. Simplifying the file name, fixed the error.
File name that gave me error: myfile-18.10.exe
File name that worked: myfile-1810.exe