Delete broken link - powershell

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;
}
}

Related

Remove-Item command is not removing a folder and its contents

I have an application that will be un installed across our estate, so I am creating a PowerShell script to do this (it will be distributed through Intune). However after the uninstall a folder and 2 files remain. I added in Remove-Item but it will not remove the folder and content even with -Force and -Recurse included as it states it is in use, but I can manually delete the folder and contents without any issues.
My script is (I have changed sensitive information)
$FileName = "C:\Users\$env:USERNAME\AppData\Local\my_app\app1.exe"
if (Test-Path $FileName) {
Write-Host "File Exists"
}
else
{
Write-Host "File Doesn't Exists"
exit
}
cd "C:\Users\$env:USERNAME\AppData\Local\my_app"
.\Update.exe --uninstall
Remove-Item -Path C:\Users\$env:USERNAME\AppData\Local\my_app -Force -Recurse
The actual error states
Remove-Item : Cannot remove the item at 'C:\Users\superuser\AppData\Local\my_app' because it is in use
At line:21 char:1
+ Remove-Item -Path C:\Users\$env:USERNAME\AppData\Local\my_app - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Remove-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RemoveItemCommand
You change locations into the same directory you are trying to delete. You need to change out of that directory. You have a few options here:
The Obvious Solution (Once You Know the Issue)
Change out of the directory:
cd .. # any path that is not part of the directory tree you want to delete
But PowerShell has some more useful ways to traverse directories. Read on for more information.
Solution 2: Windows PowerShell - Use the Location Stack
Opt for using Push-Location and Pop-Location instead of cd (aliased to Set-Location).Push/Pop-Location use the location stack. Use Push-Location to change to new directories and Pop-Location to walk backwards. In your case, this would work:
Push-Location "C:\Users\$env:USERNAME\AppData\Local\my_app"
.\Update.exe --uninstall
Pop-Location # This will return to the previous directory
Remove-Item -Path C:\Users\$env:USERNAME\AppData\Local\my_app -Force -Recurse
Solution 3: PowerShell Core - Use cd -
If you can utilize PowerShell Core, the same concept applies but PowerShell Core supports the bash-like cd - and cd + since version 6.2. Similar to using Push/Pop-Location, you can walk backwards and forwards to the directories you've been to. In your case, cd - would work like so:
cd "C:\Users\$env:USERNAME\AppData\Local\my_app"
.\Update.exe --uninstall
cd - # This will return to the previous directory
Remove-Item -Path C:\Users\$env:USERNAME\AppData\Local\my_app -Force -Recurse
From the Set-Location documentation for PowerShell Core:
PowerShell 6.2 added support for - and + as a values for the Path parameter. PowerShell maintains a history of the last 20 locations that can be accessed with - and +. This list is independent from the location stack that is accessed using the StackName parameter.

Rename file before copy to certain folder

I´m a newbie still and learning to create PowerShell scripts to make Life in IT easier.
At present I´m trying to build a script, which runs a certain Microsoft tool, scanning defined network shares in a csv file and creating an JSON output file.
Now as the pattern of this file is always the same like "Report_Username_Hostname.vba.JSON", I would like to append either the scanned directory name or even a range of numbers, fe. "Report_Username_Hostname(100).vba.JSON" or "Report_Username_Hostname(sharename).vba.JSON"
This is neccessaray as after this renaming step, I upload this and other files within this folder to another folder on different server to upload them into a Database.
I planned to run this script in in many different locations on most automatic level and they all copy the their collected files to just one upload folder.
I already tried several options I found somewhere in the deep of the Internet, but I only came to the point where the file was renamed to 0 or similar, but not to expected result.
The Powershell script doing the work is this:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$Rpath = $PSpath +'..\Reports\1st'
$localshare = $PSpath +'..\temp\1st'
$csvinputs = Import-Csv $PSpath\fileremediation_1st.csv
$uploadshare = '\\PGC2EU-WFSFR01.eu1.1corp.org\upload\'
# This section checks if the folder for scan reports is availabe and if not will create necessary folder.
If(!(test-path $Rpath))
{
New-Item -ItemType Directory -Force -Path $Rpath
}
If(!(test-path $localshare))
{
New-Item -ItemType Directory -Force -Path $localshare
}
Set-Location $Rpath
# This section reads input from configuration file and starts Ms ReadinessReportCreator to scan shares in configuration file.
ForEach($csvinput in $csvinputs)
{
$uncshare = $csvinput.sharefolder
$Executeable = Start-Process "C:\Program Files (x86)\Microsoft xxx\xxx.exe" `
-Argumentlist "-p ""$uncshare""", "-r", "-t 10000", "-output ""$localshare"""`
-Wait
Get-ChildItem -Path $localshare -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
}
# This section copies the output *.JSON file of the xxx to the share, where I they will be uploaded to DB.
Get-ChildItem -Path $localshare -Filter '*.JSON' | Where {$_.Length -ge 3} | move-item -Destination '$uploadshare'
the fileremediation_1st.csv looks like
sharefolder
\\server\sharename
Can someone please help me on this, I don´t have a clue what I´m doing wrong.
Thank you!
Current error I get is
Rename-Item : Cannot rename the specified target, because it
represents a path or device name. At
C:\temp\FileRemediation\scripts\fileremediation_V2_1st.ps1:28 char:55
+ ... share -Filter '*.JSON' | Rename-Item -NewName {$_.FullName+$uncshare}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand
As said before, I would also be fine with a dedicated range of numbers, which is append to the file name "Report_Username_Hostname(100).vba.JSON"
The perfect world would be if I could split the \server\sharename from csv file and append the sharename to my filename.
I think the issue is with:
Rename-Item -NewName {$_.FullName+$uncshare}
Your input file (Get-ChildItem) path is:
$PSpath = 'C:\temp\FileRemediation\Scripts\'
$localshare = $PSpath +'..\temp\1st'
The Rename-Item uses $_.FullName which resolves to something like this:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
The variables then contain:
$_.FullName = C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON
$uncshare = "\\server\sharename"
So Your Rename-Item ... $_.FullName+$uncshare will try to rename it to:
C:\temp\FileRemediation\Scripts\..\temp\1st\MyFile.JSON\\server\sharename
Which is not a valid path.

Unable to unzip using powershell

I am trying to unzip using powershell with below command --
powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('E:\test.zip', 'E:\'); }"
I get below log
'E:\test1.txt'
already exists."
At line:1 char:53
+ & { Add-Type -A 'System.IO.Compression.FileSystem';
[IO.Compression.ZipFile]::Ex ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : IOException
===============================
I don't see the archive being unzipped.
Update 1
E:\test1.txt already exists at the destination. How to change the command to overwrite files.
Update 2
The version of powershell available doesn't support Expand-Archive
You can't overwrite files with that method. You need to read the documentation for ZipFileExtensions.ExtractToDirectory(source, destinationDirectoryName):
This method creates the directory specified by
destinationDirectoryName. If the destination directory already exists, this method does not overwrite it; it throws an IOException
exception. The method also creates subdirectories that reflect the
hierarchy in the zip archive. If an error occurs during extraction,
the archive remains partially extracted. Each extracted file has the
same relative path to the directory specified by
destinationDirectoryName as its source entry has to the root of the archive.
If you want to use ZipFileExtensions.ExtractToDirectory() with overwrite, you'll need to extract the files to a temporary folder and then copy/move them to the desired location.
Try something like:
do {
$TempFolder = Join-Path -Path $([System.IO.Path]::GetTempPath()) -ChildPath $([System.IO.Path]::GetRandomFileName());
} while ((Test-Path -Path $TempFolder));
mkdir $TempFolder | Out-Null;
[IO.Compression.ZipFile]::ExtractToDirectory('E:\test.zip',$TempFolder);
Get-ChildItem -Path $TempFolder -Recurse | Move-Item -Destination 'E:\' -Force;
rmdir $TempFolder;
Note that this code is untested.
Below is what solved my problem
md E:\temp
move E:\test.zip E:\temp
powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('E:\temp\test.zip', 'E:\temp\'); }"
del E:\temp\test.zip
move /Y E:\temp\* E:\
rd E:\temp

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)

Parsing Shortcuts in 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.