Find a directory in multiple paths and delete it

This topic contains 0 replies, has 1 voice, and was last updated by  Forums Archives 5 years, 9 months ago.

  • Author
    Posts
  • #5963

    by i255d at 2012-11-21 07:16:09

    This is my original command:
    Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse

    This is to look in the roaming profile folder of all of our users (a couple hundred), and if they have the folder "PowerDesigner 15", I want to delete it.

    This is the output from that command:

    Marry\AppData\Roaming\Thinstall\PowerDesigner\%Common AppData%\PowerDesigner 15
    Jeff\AppData\Roaming\Thinstall\PowerDesigner\%Common AppData%\PowerDesigner 15
    Dan\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Sybase\PowerDesigner 15
    John\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Sybase\PowerDesigner 15

    Two things:
    A) it produces this output very slowly,
    B) I wanted to use a Foreach-object command to go through the output and delete the folder, but the ouput from Get-Childitem is:

    OUTPUTS
    System.IO.DirectoryInfo, System.IO.FileInfo, System.String

    And ForEach-object accepts -InputObject
    Accept pipeline input? true (ByValue)

    It seems that these are not compatable.

    Can someone help me understand a better an approch that will work for this.
    Currently reading "Learn Windows PowerShell3 in a Month of Lunches" on page 139.
    This is also my first post.

    Thanks

    by ArtB0514 at 2012-11-21 07:38:06

    You can most certainly pipe the output of Get-ChildItem into ForEach-Object without a problem. I suggest that you try this to verify that it works:
    $Folders = Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse
    $Folders | foreach-object {$_.FullName}

    I'm afraid that there's not too much you can do about speeding up searches across the network without using remoting, because (unfortunately) Get-ChildItem doesn't have a -computername parameter.

    by i255d at 2012-11-21 08:01:07

    My Goal is to delete all the "PowerDesigner 15" directories. I am not sure what you added helps me do that. Are you saying that by putting the output in a variable, it makes it an object? Also, how do I get it to delete after that?

    by ArtB0514 at 2012-11-21 10:26:28

    It seems like you are missing some very basic concepts. Putting something into a variable doesn't change its nature. Everything in PowerShell is an object. Object have two major categories of components: methods (things it "knows" how to do) and properties (things it "knows"). It can get very complicated becase each of the properties is also an object. You can see the components of a child item by running this (after you've collected $Folders object):
    $Folders[0] | Get-Member
    You will discover that what you have is a System.IO.DirectoryInfo .NET object and that it has a Delete method which has two formats. The first format, Delete(), only works on empty directories. The second format, Delete(bool recursive), takes an argument to delete the directory and all the files and directories under it. {You can find details of how that works by searching for "DirectoryInfo.Delete method" under MSDN.}
    So at this point, you should be able to test whether this works or not by entering
    $Folders[0].Delete($true)

    There might be another way to delete them and you can find that by guessing that there are more commands for processing "item". Get-Command *Item will show you that there is a Remove-Item cmdlet. Get-Help Remove-Item -Full will tell you how to use that process and gives examples.

    by Klaas at 2012-11-22 03:00:08

    If the output is correct, you can pipe this to remove-item. No need for variables or foreach constructions.

    Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse | remove-item -whatif

    The output will now be a list of operations that would be performed. If that pleases you, remove the -whatif switch and thy will be done.

    by i255d at 2012-11-23 05:51:56

    Piping into Remove-Item doesn't work, because it just adds the output to the current directory and then it can't find the directory. I think we are getting close; I am going to be working on this some more today. I am sure we can do it as described in the post prior to the previous post, but I would like to find a way to do this with cmdlets first. Also, I am still wondering if there is a faster way than Get-Childitem, which is very slow.

    by Klaas at 2012-11-23 06:10:54

    I tried this with files. To remove directories you should add the -recurse parameter to Remove-Item also.
    Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse | remove-item -Recurse -whatif

    I don't understand what you mean by "it just adds the output to the current directory and then it can't find the directory". If you use the command as I wrote, the file object found by Get- ChildItem is piped to Remove-Item, so this will be the object that is removed.

    by i255d at 2012-11-23 07:47:34

    Remove-Item : Cannot find path 'C:\Windows\system32\susan\AppData\Roaming\Thinstall\PowerDesigner\%Common
    AppData%\PowerDesigner 15' because it does not exist.
    The "C:\Windows\system32" portion of the path is my current working directory in PowerShell. The 'susan\AppData\Roaming\Thinstall\PowerDesigner\%Common\AppData%\PowerDesigner 15' portion of the path is the output from the Get-Childitem output. The actual path needed is the portion from this : -Path "\\gha01sdp333\profile$" and this: 'susan\AppData\Roaming\Thinstall\PowerDesigner\%Common\AppData%\PowerDesigner 15'

    by Klaas at 2012-11-23 08:45:12

    Strange. Maybe it has something to do with the share notation. Can you use -Path '\\gha01sdp333\c$\users' or something that is appropriate for your OS?
    I get the complete path \\server\share\directory\subdirectory back and the removal is performed on the remote server without any problem.

    by i255d at 2012-11-23 12:22:56

    Here, I am trying it with local folders and it is having the same problem.
    C:\Scripts\dani\run
    C:\Scripts\dani1\run
    C:\Scripts\dani2\run
    C:\Scripts\dani3\run
    C:\Scripts\dani4\run
    Current working directory in Power shell: C:\users\dani>

    Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse | Remove-Item -WhatIf

    Remove-Item : Cannot find path 'C:\Users\dani\dani\run' because it does not exist.
    At C:\Users\diverso\AppData\Local\Temp\Untitled4.ps1:8 char:66
    + Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse | Remove-Item -Wh ...
    + ~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (C:\Users\diverso\divero\run:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

    Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse
    dani\run
    dani1\run
    dani2\run
    dani3\run
    dani4\run

    by i255d at 2012-11-23 13:04:42

    I think I have it. I just wrote it how I would like it to work and it looks like it did:

    Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse | ForEach-Object {Remove-Item -Path C:\scripts\$_ -Recurse}

    by DexterPOSH at 2012-11-23 15:20:54

    Hi,

    The following will probably fail because of the use of -name parameter, If you look at the help it tells that if -name parameter is used then it Gets only the names of the items in the locations. If you pipe the output of this command to another command, only the item names are sent. Please note that instead of the file object the names are passed that's why it doesn't work.

    Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse | remove-item -Recurse -whatif

    Instead you could use -filter parameter which will put the objects in the pipeline and then the Foreach-object or Remove-Item any cmdlet which manipulates objects works fine.

    Hope it makes sense
    ~Cheers~

    by Klaas at 2012-11-24 04:38:27

    That's it! Great find, Dexter.
    I tested with -Filter indeed, but in my responses I just copied from the first post. I didn't know that would make the difference.

    @i255d
    I still think the version without the foreach is better. Use -Filter 'Name -like "PowerDesigner*"' (maybe this needs some tuning so you really avoid any unwanted matches) and this time you will really get the objects.
    You could try Measure-Command to compare the two methods.

    by DexterPOSH at 2012-11-25 04:21:29

    Thank you Klaas.

    Before this post I never really used -name parameter with Get-Childitem , so I guess I really learned something new here.

    ~Cheers~

    by i255d at 2012-11-26 12:16:33

    I have never had much luck with Forums. A lot of the time, it is like ease dropping on a private conversation, a conversation, where you don't know the people you are listening too. Dexter says he learned something new, but he doesn’t elaborate on what he learned. Klass says to use –filter parameter, but he doesn’t give a reference to where he would put it, or any referenced as to where someone might find information on how to make it work. The example: -Filter 'Name -like "PowerDesigner*"' doesn’t work at all.
    So far, the only script that has worked is the one I came up with and posted myself, and it is so slow, that I can’t believe there isn’t a better way. It also doesn’t work in v2 of PowerShell.

    by ArtB0514 at 2012-11-26 12:52:18

    The reason that Remove-Item is giving you the error message about not finding the file to delete is that it is using the Name property from the pipeline object and joining it to the current path. Since your files are not located on the current computer, this will fail. I'm not sure that Remove-Item can delete an object on another computer, but if it can, you will have to specify the FullName property in order to identify it. Try this to see if you get better results (requires PowerShell 3):

    Get-ChildItem -Path "\\gha01sdp333\profile$" -Name "PowerDesigner 15" -Directory -Recurse | foreach {remove-item $_.FullName -Recurse -whatif}

    You will probably still get some error messages if there are child folders in the PowerDesigner folders.

    by DonJ at 2012-11-26 14:12:22

    Correct – with a simple Name (e.g., MyFile.txt) Remove-Item will fail unless that items exists in the current location. It can delete from a remote machine, provided FullName (or some other property) contains a UNC, or you've mapped a drive for it to work with. Good point!

    by Klaas at 2012-11-27 10:19:49

    I'm sorry, I didn't use the right filter syntax, it should be Get-ChildItem -Path "\\gha01sdp333\profile$" -Filter "*PowerDesigner 15*" -Directory -Recurse | remove-item -Recurse -whatif
    As everyone has pointed out, it won't work if Remove-Item receives only a name. As Dexter found, that happens when using -Name, but when using -Filter there is more output, including the path. And that's what remove-item needs.
    Obviously I don't have a computer named gha01sdp333 and I don't have Powerdesigner installed, but I created 'test' directory with subdirectories on a remote server and the command above does work. I'm using Powershell V3, but the help files are for V2 and describe the same functionality:
    Get-Help Get-ChildItem -online There's even an example exactly like this.
    And I still say there's no need for Foreach.

    by i255d at 2012-11-27 14:12:48

    Here is what actually worked. I still think there has to be a faster way, this takes hours for about 200 users. I had to remove the -Directory for it to work in V2. I also had a 15 and 16 folder for PowerDesigner that I found and needed to be removed. Should I start another post to see if we can find a faster way. The server name is an NFS share. I had to make it work in V2 because it was taking so long, I had to run it from a server so I could go home. So I don't actually know how long it took.

    Get-ChildItem -Path "\\gha01sdp333\profile$" -Filter "PowerDesigne*" -Recurse -ErrorAction SilentlyContinue | Remove-Item -Recurse

    by DexterPOSH at 2012-11-28 07:10:11

    Sorry If I was not able to explain it elaborately.

    I replied to this while I was at work.
    I heard J Snover say at one of the podcasts that Get-ChildItem is very slow with Network shares in PowerShell v2, but in V3 they have made few changes to make it perform better..to improve the performance you could try updating to PowerShell v3.
    ~Regards~

    by i255d at 2012-12-03 13:40:05

    I ran a test running this command in v2 and v3

    Get-ChildItem -Path "\\gha01sdp333\profile$" -Recurse

    It took 2 hour and 18 minutes in v2
    It took 1 hour and 10 minutes in v3

    by megamorf at 2012-12-05 22:08:22

    [quote="i255d"]Here, I am trying it with local folders and it is having the same problem.
    C:\Scripts\dani\run
    C:\Scripts\dani1\run
    C:\Scripts\dani2\run
    C:\Scripts\dani3\run
    C:\Scripts\dani4\run
    Current working directory in Power shell: C:\users\dani>

    Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse | Remove-Item -WhatIf

    Remove-Item : Cannot find path 'C:\Users\dani\dani\run' because it does not exist.
    At C:\Users\diverso\AppData\Local\Temp\Untitled4.ps1:8 char:66
    + Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse | Remove-Item -Wh ...
    + ~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (C:\Users\diverso\divero\run:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

    Get-ChildItem -Path C:\Scripts -Name "run" -Directory -Recurse
    dani\run
    dani1\run
    dani2\run
    dani3\run
    dani4\run[/quote]

    Here's the problem:

    [1]NEM-PC {C:\Users\nem}
    >gci -path "\\$env:computername\C$\Chocolatey\lib" -name "tools" -Recurse
    autohotkey.1.1.5.1\tools
    Console2.2.0.0.20120225\tools
    expresso.3.0.4334.20120225\tools
    putty.0.62\tools

    [2]NEM-PC {C:\Users\nem}
    >gci -path "\\$env:computername\C$\Chocolatey\lib" -name "tools" -Recurse | select -f 1 | gm

    TypeName: System.String

    versus

    [3]NEM-PC {C:\Users\nem}
    >gci -path "\\$env:computername\C$\Chocolatey\lib" -filter "tools" -Recurse

    Directory: \\NEM-PC\C$\Chocolatey\lib\autohotkey.1.1.5.1

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 09.09.2012 22:01 tools

    Directory: \\NEM-PC\C$\Chocolatey\lib\Console2.2.0.0.20120225

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 09.09.2012 21:27 tools

    Directory: \\NEM-PC\C$\Chocolatey\lib\expresso.3.0.4334.20120225

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 09.09.2012 21:36 tools

    Directoy: \\NEM-PC\C$\Chocolatey\lib\putty.0.62

    Mode LastWriteTime Length Name
    ---- ------------- ------ ----
    d---- 09.09.2012 21:36 tools

    [4]NEM-PC {C:\Users\nem}
    >gci -path "\\$env:computername\C$\Chocolatey\lib" -filter "tools" -Recurse | select -f 1 | gm

    TypeName: System.IO.DirectoryInfo

    And make sure you have the correct version of powershell for the parameters you use:

    Powershell Version 2
    [3]NEM-PC {C:\Users\nem}
    >$PSVersionTable

    Name Value
    ---- -----
    CLRVersion 2.0.50727.5466
    BuildVersion 6.1.7601.17514
    PSVersion 2.0
    WSManStackVersion 2.0
    PSCompatibleVersions {1.0, 2.0}
    SerializationVersion 1.1.0.1
    PSRemotingProtocolVersion 2.1

    [4]NEM-PC {C:\Users\nem}
    >Get-Command Get-ChildItem | Select-Object -ExpandProperty Parameters

    Key
    ---
    Path
    LiteralPath
    Filter
    Include
    Exclude
    Recurse
    Force
    Name
    Verbose
    Debug
    ErrorAction
    WarningAction
    ErrorVariable
    WarningVariable
    OutVariable
    OutBuffer
    UseTransaction

    Versus

    Powershell Version 3
    [18]NEM-PC {C:\Users\nem}
    >$psversiontable

    Name Value
    ---- -----
    WSManStackVersion 3.0
    PSCompatibleVersions {1.0, 2.0, 3.0}
    SerializationVersion 1.1.0.1
    BuildVersion 6.2.9200.16398
    PSVersion 3.0
    CLRVersion 4.0.30319.296
    PSRemotingProtocolVersion 2.2

    [19]NEM-PC {C:\Users\nem}
    >Get-Command Get-ChildItem | Select-Object -ExpandProperty Parameters

    Key
    ---
    Path
    LiteralPath
    Filter
    Include
    Exclude
    Recurse
    Force
    Name
    Verbose
    Debug
    ErrorAction
    WarningAction
    ErrorVariable
    WarningVariable
    OutVariable
    OutBuffer
    UseTransaction
    Attributes
    Directory
    File
    Hidden
    ReadOnly
    System

    by teezee at 2013-02-13 17:00:43

    here is what I did. note that you require powershell 3.0 I believe to get the -directory switch to work. also note that the -directory parameter will reduce the process time.

    function deleteallmatchingfolder
    {
    $todelete = Get-ChildItem -Directory -recurse -Path 'H:\posh-test - Copy\'

    foreach ($folder in $todelete)
    {

    if ($folder.Name -match "folder3")
    {
    write-host $folder.fullname
    #$folder.Delete($true)
    }
    }
    }
    deleteallmatchingfolder

    simply unquote # to delete folders.

    I just thought about sharing another solution..

    by i255d at 2013-03-05 08:40:25

    What does the – Copy\' get you?

    'H:\posh-test – Copy\'

    by teezee at 2013-03-07 18:05:24

    its the name of the folder :X quote'folder'quote

You must be logged in to reply to this topic.