Parsing Shortcuts in Powershell - powershell

I have some code which is trying to make a copy of a directory which contains shortcuts:
# Create a directory to store the files in
mkdir "D:\backup-temp\website.com files\"
# Search for shortcuts so that we can exclude them from the copy
$DirLinks = Get-ChildItem "\\web1\c$\Web Sites\website\" -Recurse | ? { $_.Attributes -like "*ReparsePoint*" } | % { $_.FullName }
# Execute the copy
cp -recurse -Exclude $DirLinks "\\web1\c$\Web Sites\website\*" "D:\backup-temp\website.com files\"
But when I execute the script I get the following error:
Copy-Item : The symbolic link cannot be followed because its type is disabled.
At C:\scripts\backup.ps1:16 char:3
+ cp <<<< -recurse "\\web1\c$\Web Sites\website\*" "D:\backup-temp\website.com files\"
+ CategoryInfo : NotSpecified: (:) [Copy-Item], IOException
+ FullyQualifiedErrorId :
System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand
It seems the script is getting hung up on a symbolic link (I'm assuming the shortcut) that I'm trying to exclude in the fourth line of the script.
How can I tell powershell to ignore/exclude shortcuts?
Thanks,
Brad

If you are on V3 or higher you can eliminate the reparse points like so:
Get-ChildItem "\\web1\c$\Web Sites\website" -Recurse -Attributes !ReparsePoint |
Copy-Item -Dest "D:\backup-temp\website.com files"
On V1/V2 you can do this:
Get-ChildItem "\\web1\c$\Web Sites\website" |
Where {!($_.Attributes -bor [IO.FileAttributes]::ReparsePoint)} |
Copy-Item -Dest "D:\backup-temp\website.com files" -Recurse

So it turns out that the issue I faces is explained in this Microsoft Blog Post:
http://blogs.msdn.com/b/junfeng/archive/2012/05/07/the-symbolic-link-cannot-be-followed-because-its-type-is-disabled.aspx
Essentially on the server I am running the powershell script from I needed to run the following command:
fsutil behavior set SymlinkEvaluation R2R:1
This allows Remote to remote symbolic links. Once this is in place the above powershell commands run as expected without errors.

Related

Powershell script to rename Files adding Last Modified date to name, script won't run in sub directories

I have an old server archived and would like to rename all the files by adding the last modified date to the file name.
There are many layers of folders in the directory structure.
I have tried a few different versions of scripts and the first level works fine, then it errors on the sub folders.
Error:
Rename-Item : Cannot rename because item at 'Stand.doc' does not exist.
At line:1 char:42
+ ... ch-Object { Rename-Item $_ -NewName ("{0}-{1}{2}" -f $_.BaseName,$_.L ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand*
Stand.doc is a file from a sub directory.
Semi-Working script:
Get-ChildItem -recurse |Foreach-Object { Rename-Item $_ -NewName ("{0}-{1}{2}" -f $_.BaseName,$_.LastWriteTime.ToString('"Last_Mod_Date_"mmddyyyy'),$_.Extension) }
Thank you
I've been able to reproduce this with Windows PowerShell (5.1) after all but I cannot reproduce it in PowerShell Core 7.2.3. I'm not quite sure what the issue here is but this answer should only be considered relevant for PowerShell Core. I will try to revisit this later to see if I can't figure out what's going on with PowerShell 5.1.
You will want to use the -File parameter with Get-ChildItem. The following should work for you to only return nested files so you don't accidentally try renaming directories:
Get-ChildItem -Recurse -File | Foreach-Object {
Rename-Item -WhatIf $_ -NewName ( "{0}-{1}{2}" -f $_.BaseName, $_.LastWriteTime.ToString('"Last_Mod_Date_"mmddyyyy'), $_.Extension )
}
I've added a -WhatIf parameter to Rename-Item, once you confirm the correct file list will be renamed, you can remove this to actually have the rename operation work.

What does it mean "Could not find a part of the path"?

Is there a limit to the size of the path the get-childitem and select-string can handle? If yes what is the alternative?
When I run the following command on the path:
PS E:\KINGSTON backup5\03 Learning\Softwares\Mathematica\Mathematica 12\Mathematica Directories Backup2\C,Users,atfai,AppData,Roaming,Mathematica\Paclets\Repository\SystemDocsUpdate1-12.0.0\Documentation\English\Workflows> get-childitem -recurse -filter "*.nb" -file | select-string -pattern ".*ProcessObject.*" -casesensitive
I get the following error
select-string : The file E:\KINGSTON backup5\03
Learning\Softwares\Mathematica\Mathematica 12\Mathematica Directories
Backup2\C,Users,atfai,AppData,Roaming,Mathematica\Paclets\Repository\SystemDocsUpdate1-12.0.0\Documentation\English\Workflows\ChangeTheStyleOfPointsInA2DScatterPlot.nb
cannot be read: Could not find a part of the path 'E:\KINGSTON
backup5\03 Learning\Softwares\Mathematica\Mathematica 12\Mathematica
Directories
Backup2\C,Users,atfai,AppData,Roaming,Mathematica\Paclets\Repository\SystemDocsUpdate1-12.0.0\Documentation\English\Workflows\ChangeTheStyleOfPointsInA2DScatterPlot.nb'.
At line:1 char:47
+ ... nb" -file | select-string -pattern ".ProcessObject." -casesensitive ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Select-String], ArgumentException
+ FullyQualifiedErrorId : ProcessingFile,Microsoft.PowerShell.Commands.SelectStringCommand
Moreover if I run the same command on the following path:
PS E:\Computer Backup\Downloads - Current\Windows 10 Optimization\SoftwareDistribution.old3\Download\736aed4d238d4999f5ea5b04589077ed\Package_for_RollupFix~~amd64~~17134.677.1.6\x86_wcf-system.servicemodel_b03f5f7f11d50a3a_10.0.17134.254_none_d5ff175e12d127c0> get-childitem -recurse -filter "*.nb" -file | select-string -pattern ".*ProcessObject.*" -casesensitive
I get the error this time from get-childitem
get-childitem : Could not find a part of the path 'E:\Computer
Backup\Downloads - Current\Windows 10
Optimization\SoftwareDistribution.old3\Download\736aed4d238d4999f5ea5b
04589077ed\Package_for_RollupFix~~amd64~~17134.677.1.6\x86_wcf-system.servicemodel_b03f5f7f11d50a3a_10.0.17134.254_none_d5ff175e12d127c0'.
At line:1 char:1
+ get-childitem -recurse -filter "*.nb" -file | select-string -pattern ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (E:\Computer Bac...5ff175e12d127c0:String) [Get-ChildItem],
DirectoryNotFoundException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
What does it mean "Could not find a part of the path"? The drive E has NTFS file system which is supported by Windows so its powershell commands should be able to handle it? What is going on here?
BTW I can access both paths from the Windows explorer and open the files in the notepad. So the paths exist and files are clearly not corrupt or inaccessible.
The problem is, that long paths aren't enabled on your OS, so there is a limit of 260 characters.
Depending on the version of windows you are running, this can be fixed by enabling the group policy Local Computer Policy > Computer Configuration > Administrative Templates > System > Filesystem > NTFS > Enable NTFS long paths.
If you don't have that option, changing the value of the registry key LongPathsEnabled at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem from 0 to 1 does the job as well.
If you can't use the registry or group policy fix of the other answer you may be able to work around this by using the prefix \\?\E:\folder1\...
To specify an extended-length path, use the "\?" prefix. For example, "\?\D:\very long path".
[...]
The "\?" prefix can also be used with paths constructed according to
the universal naming convention (UNC). To specify such a path using
UNC, use the "\?\UNC" prefix. For example, "\?\UNC\server\share",
where "server" is the name of the computer and "share" is the name of
the shared folder.
Ref: https://learn.microsoft.com/en-ca/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd

Count number of folders in directory and ignore shortcuts

I have a script which will accurately tell me how many folders are in a directory, and the subdirectories within. However, for one directory which I am working with, there are shortcut folders which seem to cause the script to fail.
Below is the error message which I receive:
Get-ChildItem : Could not find a part of the path 'C:\Folder\SubFolder\folder1\jpos'.
At C:\Desktop\Script Files\fileCount.ps1:34 char:10
+ $items = Get-ChildItem C:\Folder\SubFolder\ -Recurse
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ReadError: (C:\Folder\SubFolder\folder1\jpos:String) [Get-ChildItem],
DirectoryNotFoundException
+ FullyQualifiedErrorId :
DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand`
The script runs fine for directories without shortcuts, but it seems to always fail when there are shortcuts within the directory.
Below is the code snippet for this section:
$items = Get-ChildItem C:\Folder\SubFolder -Recurse
$termFolder = ($items | Where-Object {$_.PSIsContainer}).count
Is there any way to skip over shortcuts or a better way to do a folder count?
(gci path |?{$_.Extension -ne ".lnk"}).Count
Shortcuts have .lnk extension and gci means Get-Childitem.
Just use -directory like this (for PowerShell 3 or +):
$items = Get-ChildItem C:\Folder\SubFolder -Recurse -Directory
$termFolder = $items.Count
If you don't need the directory collection folder subsequently in script, then you can simply use
$countDirs = $(Get-ChildItem -path c:\folder\subfolder -Recurse -Directory).count

Powershell Remove-Item Cmdlet error

I'm using powershell to remove a directory with the command:
Remove-Item $pathAsString -Recurse -Force
However, it gives me the following error:
Remove-Item : Cannot remove the item at 'C:\Path' because it is in use.
At line:1 char:1
+ Remove-Item "C:\Path" -Recurse
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Remove-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RemoveItemCommand
I thought that was odd, because the directory shouldn't be in use. I can go into file explorer and delete the directory manually. I'm not really sure why this behavior is occurring. I'm fairly new to powershell, so don't understand exactly how it behaves.
My scripts interaction with the program includes:
Creating the folder
Downloading an MSI to the folder
Setting a variable to represent the MSI stored in the folder. Like so:
$MSIVariable = Get-ChildItem $Path | Where {&_.Name -eq "MSIName.msi"}
I'm assuming that something to do with the folder is within a stream of some sort, but don't know how I'd fix this issue.
EDIT:
Here is the code I use involving the folder:
Creating the Folder:
if(!(Test-Path $MSILocation))
{
New-Item $MSILocation -ItemType directory
}
Downloading the MSI:
$webClient = (New-Object System.Net.WebClient)
$downloadLocation = Join-Path $MSILocation $MSIName
$webClient.DownloadFile($downloadURL, $downloadLocation)

Delete broken link

I need to delete all the content of a folder which may include broken links among others. The folder path is provided by a variable. Problem is that PowerShell fails to remove the broken links.
$folderPath = "C:\folder\"
Attempt 1:
Remove-Item -Force -Recurse -Path $folderPath
Fails with error:
Remove-Item : Could not find a part of the path 'C:\folder\brokenLink'.
At line:1 char:1
+ Remove-Item -Force -Recurse -Path $folderPath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\folder\brokenLink:String) [Remove-Item], DirectoryNot
FoundException
+ FullyQualifiedErrorId : RemoveItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Attempt 2:
Start-Job { cmd /c rmdir $folderPath }
Fails because $folderPath gets passed as is instead of its value:
Start-Job { cmd /c rmdir $folderPath } | select command
Command
-------
cmd /c rmdir $folderPath
Any suggestion besides using the .NET framework?
EDIT
By broken link I'm referring to a folder which points to a previously mounted partition, that doesn't exist anymore. The folder is still available but when attempting to navigate into it this error occurs because the destination doesn't exist anymore:
Error:
C:\folder\brokenLink refers to a location that is unavailable. It
could be on a hard drive on this computer, or on a network. Check to
make sure that the disk is properly inserted, or that you are
connected to the Internet or your network, and then try again. If it
still cannot be located, the information might have been moved to a
different location.
This will work:
$folderPath = "C:\folderContaingBrokenSymlinks\";
$items = ls $folderPath -Recurse -ea 0;
foreach($item in $items){
if($item.Attributes.ToString().contains("ReparsePoint")){
cmd /c rmdir $item.PSPath.replace("Microsoft.PowerShell.Core\FileSystem::","");
}
else{
rm -Force -Recurse $item;
}
}