Remove-Item -Recurse -Force can't remove symlinks - powershell

It seems that Remove-Item -Recurse -Force cannot deal with removing symlinks. How do I recursively delete everything from a given directory with symlinks made all over the place?
MWE:
PS C:\Users\Administrator\Desktop\test> mkdir foo
Directory: C:\Users\Administrator\Desktop\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/30/2020 11:58 AM foo
PS C:\Users\Administrator\Desktop\test> mkdir bar
Directory: C:\Users\Administrator\Desktop\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 7/30/2020 11:58 AM bar
PS C:\Users\Administrator\Desktop\test> New-Item -ItemType SymbolicLink -Path foo -Name bar -Value C:\Users\Administrator\Desktop\test\bar
Directory: C:\Users\Administrator\Desktop\test\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----l 7/30/2020 11:59 AM bar
PS C:\Users\Administrator\Desktop\test> Remove-Item -Recurse -Force foo
Remove-Item : There is a mismatch between the tag specified in the request and the tag present in the reparse point
At line:1 char:1
+ Remove-Item -Recurse -Force foo
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Remove-Item], Win32Exception
+ FullyQualifiedErrorId : System.ComponentModel.Win32Exception,Microsoft.PowerShell.Commands.RemoveItemCommand

The actual CMD equivalent to Remove-Item -Recurse -Force is:
cmd /c rmdir /s /q foo
as it will delete symlinks also in subdirectories. This seems to be good enough for me.

Looks like you are running into the same issue as mentioned here:
https://github.com/powershell/powershell/issues/621
And workaround which is mentioned in this thread is:
Get-ChildItem $somepath -Attributes ReparsePoint | % { $_.Delete() }
Or you can gather more information here:
https://github.com/PowerShell/PowerShell/pull/11331

There's always cmd. Wmi and powershell can't even delete profiles these days because of links.
cmd /c del bar

Related

Powershell Copy-Item -recurse does not pick up new directory

I'm creating a binary PS module with PlatyPS help. I have a local poor-man's deploy script like this (PS 5.1):
$modulepath= "$Env:USERPROFILE\Documents\WindowsPowerShell\Modules"
$releasePath = ".\bin\release\net472"
# build project
dotnet build -c release
# build documentation
# requires PlatyPS module
New-ExternalHelp -Path .\docs -OutputPath $releasePath\en-US -Force
ls $releasePath # debug
# copy files
Get-ChildItem -Path $releasePath | Copy-Item -Destination $modulepath\PoshCommence -Recurse -Force
ls $modulepath\PoshCommence # debug
This ouputs the following surprising result:
Directory: X:\CustomModules\PoshCommence\bin\release\net472
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 17-2-2021 00:31 en-US
-a---- 17-2-2021 00:24 36352 PoshCommence.dll
Directory: C:\Users\XXX\Documents\WindowsPowerShell\Modules\PoshCommence
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 17-2-2021 00:31 871 about_PoshCommence.help.txt <- from en-US folder
-a---- 17-2-2021 00:24 36352 PoshCommence.dll
-a---- 17-2-2021 00:31 141080 PoshCommence.dll-Help.xml <- from en-US folder
None of the directories exist prior to running the script. I deleted the 'bin' project folder as well as the 'PoshCommence' module folder.
It seems either Get-ChildItem or Copy-Item -Recurse do not pick up the newly created 'en-US' directory, but the contents of it do get copied to the root level. If I run the script a second time (without deleting folders), it works as expected (except I still have docs stuff in the root of the module I don't want).
That has me stumped. I have tried -Verbose on everything, I put Start-Sleep after every line thinking operations may need time, but to no avail. Why isn't the 'en-US' folder picked up the first time?
Answering my own question. My confusion stems from the fact that
Copy-Item -Path $source -Destination $destination -Recurse
Works differently depending on whether the folder in $destination already exists or not.
So in the end all it took was
if (!(Test-Path $modulepath\PoshCommence)) { mkdir $modulepath\PoshCommence }
prior to the copying.

How do I overwrite a file using PowerShell?

New-Item -Path "C:\aws" -Name "script.ps1" -ItemType "file" -Value "text in file"
I am trying to create a file using the above command, if the file already exists I have to replace it with new file, it will have same file name. Please help
Use the force — specifically, the -Force parameter...
New-Item -Path "C:\aws" -Name "script.ps1" -ItemType "file" -Value "text in file" -Force
Whether script.ps1 already exists or not, upon success it will contain the exact content text in file.
Its use is also demonstrated in example #9 of the New-Item documentation...
Example 9: Use the -Force parameter to overwrite existing files
This example creates a file with a value and then recreates the file using -Force. This overwrites The existing file and it will lose it's content as you can see by the length property
PS> New-Item ./TestFile.txt -ItemType File -Value 'This is just a test file'
Directory: C:\Source\Test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/1/2020 8:32 AM 24 TestFile.txt
New-Item ./TestFile.txt -ItemType File -Force
Directory: C:\Source\Test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 5/1/2020 8:32 AM 0 TestFile.txt
Omitting -Force from the second invocation of New-Item produces the error New-Item : The file '...\TestFile.txt' already exists..

Powershell Copy-Item not keeping folder structure

I have the below script to copy data from a local folder to a remote folder created with the current date. However the files are copying but the folder structure is not.
$Date = (Get-Date).ToString("MMddyyyy"),$_.Extension
$Source = "E:\Folder1\\*"
$Dest = "\\Server\Share\Folder2"
$Username = "Username"
$Password = ConvertTo-SecureString "Password" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential($Username, $Password)
Remove-PSDrive -Name T
Start-Sleep -s 1
New-PSDrive -Name T -PSProvider FileSystem -Root $Dest -Credential $mycreds -Persist
if (!(Test-Path "T:\$Date"))
{
md -Path "T:\$Date"
}
Get-ChildItem -Path $Source -Recurse | % { Copy-Item -Path $_ -Destination "T:\$Date" -Container -Force -Verbose }
Could anyone advise where I am going wrong here?
Thank you.
Nice script, I think we can get this sorted in no time!
Why this happened
The reason this is failing is in this step right here:
Get-ChildItem -Path $Source -Recurse
The -Recurse switch is causing you pain. To illustrate why this is, I created a simple folder structure.
When you run Get-ChildItem -Path $Source -Recurse alone, you'll get a recursive listing of all files in the $Source path, like so:
PS C:\temp\stack> Get-ChildItem -Recurse
Directory: C:\temp\stack
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/4/2017 10:50 AM Source
Directory: C:\temp\stack\Source
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/4/2017 10:57 AM 1
d----- 8/4/2017 10:57 AM 2
d----- 8/4/2017 10:57 AM 3
d----- 8/4/2017 10:57 AM 4
Directory: C:\temp\stack\Source\1
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 8/4/2017 10:57 AM 20 Archive.rar
-a---- 8/4/2017 10:56 AM 0 File01.bmp
Well, in the next step of your script, you pipe that output over to Copy-Item for every single file.
You're basically expressly telling PowerShell 'take this folder and all of it's subfolders and everything, and dump them all in this one folder, ignoring the folder structure'
How to fix
What you really want to do is simply move the -Recurse parameter over to Copy-Item, and you're done :)
Get-ChildItem -Path $Source |
Copy-Item -Destination "T:\$Date" -Container -Recurse -Force -Verbose
Hope that helps, have a nice 🎃day!
This question is a few years old, but in case someone arrives here like I did...
In another post, a user suggested using robocopy. It worked great for me:
robocopy "source/folder" "target/folder" "*.file_extension" /s
This command copies from the source folder the files that match the given filter, replicating the folder structure in the destination folder.
In this case, it would be used like:
robocopy "E:\Folder1\" "\\Server\Share\Folder2" "*" /s

PowerShell: Copy-Item fails despite the same process working with Windows Explorer

I have a script that needs to copy files on a regular basis (every hour). I can open the source and destination folder using windows explorer and copy the file without issue.
However, if I try the same thing in PowerShell I get an Access to the path is denied error. I've checked the permissions on the share and I have full access. Why does this fail through PowerShell?
Copy-Item command:
Copy-Item \\idmststtrm2\tns_admin$\tnsnames.ora -Destination \\bts13r2b\tnsnames -Force
Errors:
Copy-Item : Access to the path '\\bts13r2b\tnsnames\tnsnames.ora' is denied.
At line:1 char:1
+ Copy-Item \\idmststtrm2\tns_admin$\tnsnames.ora -Destination \\bts13r2b\tnsnames ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\idmststtrm2\tns_admin$\tnsnames.ora:FileInfo) [Copy-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : CopyFileInfoItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand
Copy-Item : Access to the path '\\bts13r2b\tnsnames\tnsnames.ora' is denied.
At line:1 char:1
+ Copy-Item \\idmststtrm2\tns_admin$\tnsnames.ora -Destination \\bts13r2b\tnsnames ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Copy-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.CopyItemCommand
Edits:
When I execute a Get-ChildItem against the destination path, I'm able to see the folder contents.
Results from get-item:
get-item \\idmststtrm2\tns_admin$\tnsnames.ora
Directory: \\idmststtrm2\tns_admin$
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 3/10/2017 8:49 AM 14143 tnsnames.ora
get-item \\bts13r2b\tnsnames\tnsnames.ora
Directory: \\bts13r2b\tnsnames
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 3/8/2017 9:51 AM 15991 tnsnames.ora
get-item \\bts13r2b\tnsnames
Directory:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 3/21/2017 11:14 AM tnsnames
Tried using xcopy:
xcopy \\idmststtrm2\tns_admin$\tnsnames.ora \\bts13r2b\tnsnames\tnsnames.ora
Access is denied.
This problem is due to permissions writing to a network share. While the share permissions were set correctly, the NTFS permissions were missing. A system administrator will need to ensure both sets of permissions allow for the account to write to the folder. Once this was updated correctly the script was able to perform a copy to the network share.
I know this is old, but I had a hair-pulling experience trying to get a scheduled job (running as a GMSA) to work calling a .ps1 using Copy-Item and getting the same "Access to the path ... is denied" error. I checked and double-check permissions on the remote shares - both Share permissions and NTFS permissions. It ran successfully with my login, it ran successfully with Admin login.
Finally, just for grins, I changed the Share permissions from "All Users" to "Everyone" and it started working! Therefore, it appears that GMSA accounts are not part of "All Users". I would have never guessed!
Hopefully this saves someone 10 hours of fruitless labor...
You have the correct idea, but what if you try using the 'Administrative Share' to access the other system.
Created some standard variables: $Source and $Target. Now we use Get-ChildItem and the switch -Path to grab the file or directory we need. Then we use Copy-Item and the switch -Force to send the file to the other server. This method should work, but will describe another method.
I assume it would look something like this.
$Source = "\\idmststtrm2\c$\app\oracle\product\11.2.0\dbhome_1\network\admin\tns_admin$\tnsnames.ora"
$Target="\\bts13r2b\c$\app\oracle\product\11.2.0\dbhome_1\network\admin\tnsnames"
Get-ChildItem -Path $Source | Copy-Item -Destination $Target -Force
Another option is to make sure that you first have write access to both shared directories. Once that is verified, we run the following:
$Source="\\idmststtrm2\tns_admin$\tnsnames.ora"
$Target="\\bts13r2b\tnsnames"
Get-ChildItem -Path $Source | Copy-Item -Destination $Target -Force
#(Get-Acl $Source).Access #Verify $Source Access
#(Get-Acl $Target).Access #Verify $Target Access
Let us know if this works.
Try opening powershell as an administrator, some times that causes this issue

How to recursively search a directory for all files including hidden files in hidden directories, with PowerShell?

To recursively search for a hidden file, I am using:
gci -Path C:\ -Filter part_of_filename* -Recurse -Force | where { $_.Attributes -match "Hidden"}
The output shows me many errors exactly like this (depending on the path):
Get-ChildItem : Access to the path 'C:\Documents and Settings' is
denied. At
C:\Users\USERNAME\Documents\powershell\searchdisk.ps1:10
char:5
+ gci <<<< -Path C:\ -Filter part_of_filename* -Recurse -Force | where { $_.Attributes -match "Hidden"}
+ CategoryInfo : PermissionDenied: (C:\Documents and Settings:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
I need a PowerShell command that recursively searches ANY directory including hidden directories and shows me all files including hidden files of the name part_of_filename* (for this example)
I ran the command using PowerShell ISE as Administrator. It won't search inside directories like
C:\Windows\System32\LogFiles\WMI\RtBackup
You're doing it right. Just run it in an elevated console and remove the filter. If you don't care about permission errors, append -ErrorAction SilentlyContinue:
Get-ChildItem -Path C:\ -Filter lush* -Recurse -Force `
-ErrorAction SilentlyContinue
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-arhs 25.09.2013 12:16 1208 lush.asx
lush.asx has the ReadOnly, Hidden and System attributes.
You may also want to pipe to | select Name, Length, Directory to get rid of that unfortunate Directory: C:\ line. There's also a DirectoryName if you want the full path without the filename.