Self Delete Folder with scripts powershell

我的梦境 提交于 2021-02-08 06:36:44

问题


I have been trying to have powershell or batch scripts delete a folder that contains all my scripts when I am finished. Originally I tried Remove-Item -Path "C:\Tool" -Recurse -Force which worked no problem if run as a script for a location outside of C:\Tool. It would complain the files were in use when run from a script within. After some research I found &cmd.exe /c rd /s /q "C:\Tool" which worked much better, but even though I closed the GUI, the command wouldn't delete the img files/folders in use.

Both the above commands run perfectly when initiated from a USB drive.

Previously I created a second script in the temp folder which would delete all the files and then itself. I am looking for a new way to do this to streamline the new design I'm working on. I want the script to work from either within C:\Tool or from a USB drive.

The control flow is such:
1)Script loads all functions
2)GUI is displayed (which contains imgs)
3)Button is pressed
4)GUI is closed
5)Folder containing script is deleted

Step 5 is my issue as already explained. Not all files are removed by either attempted commands and variations of commands.

I want step 5 to work regardless is command is called from a button on the GUI, it autoruns as a part of the script, or a script in another location such as a USB calls it to delete the folder C:\Tool


回答1:


We don't know the specifics of how your GUI is displayed, but, assuming you're using a WinForms GUI constructed in PowerShell code, your problem may be how your GUI construction code loads images from files in the folder that you later want to delete.

Notably, if you use something like:

[Bitmap]::new(<file-path>)
[System.Drawing.Image]::FromFile(<file-path>)

the specified file apparently stays open for the remainder of the PowerShell session, and you won't be able to delete your folder.

The solution is to create a new image instance in memory that copies the loaded-from-file image, and to then dispose of the loaded-from-file image, which releases the lock on the underlying file, as demonstrated in this [C#] answer.

Here's a minimal script, demo.ps1, that demonstrates the approach:

  • Save it to its own, temporary, throw-away folder.

  • Copy a small image file named demo.png into the same folder.

  • Then invoke it as <temp-folder>/demo -SelfDestruct to see it in action; the need to specify
    -SelfDescript is a precaution, given that accidental invocation would wipe out the entire folder in which the script lives.

demo.ps1:

param([switch] $SelfDestruct)

# Load the WinForms assembly.
Add-Type -AssemblyName System.Windows.Forms    

# Create the form.
$form = New-Object system.Windows.Forms.Form -Property @{
    ClientSize = New-Object System.Drawing.Point 400,100
    Text       = "Dialog"
}    

# Add a PictureBox control that loads its image from 'demo.png'
$form.Controls.Add((New-Object System.Windows.Forms.PictureBox  -Property @{
Image = & { 
    # Load the image from file in the same folder as a script into
    # a temporary variable.
    $tmpImg = [System.Drawing.Image]::FromFile((Join-Path $PSScriptRoot 'demo.png')) 
    # Create an in-memory copy of the image. 
    New-Object System.Drawing.Bitmap $tmpImg
    # Dispose of the from-file image, which releases the file.
    $tmpImg.Dispose()
}
Location = New-Object System.Drawing.Point 10, 10
}))


# Show the form and wait for the use to close it.
$null = $form.ShowDialog()

if ($SelfDestruct) { # Remove the running script's entire folder.
  if ("$($PWD.Path)\" -like "$PSScriptRoot\*") {                                                      #"
      Push-Location C:\ # must switch to different dir. before deleting.
  }
  # Remove the entire folder.
  Remove-Item -literalpath $PSScriptRoot -Recurse -Force
  exit
}

Here's a variant that triggers the removal by button click, via an event handler:

param([switch] $SelfDestruct)

Add-Type -AssemblyName System.Windows.Forms

function remove-OwnFolder {
    # If the current dir. is in the subtree of the folder to delete, 
    # we must switch to different dir. before deleting.
    if ("$($PWD.Path)\" -like "$PSScriptRoot\*") {                                                      #"
        Push-Location C:\ 
    }
    # Remove the script's parent folder as a whole.
    Remove-Item -literalpath $PSScriptRoot -Recurse -Force
}

# Create the form.
$form = New-Object system.Windows.Forms.Form -Property @{
    ClientSize = New-Object System.Drawing.Point 400,100
    Text       = "Dialog"
}    

# Add a PictureBox control that loads its image from 'demo.png'
$form.Controls.Add((New-Object System.Windows.Forms.PictureBox  -Property @{
    Image = & { 
        # Load the image from file in the same folder as a script into
        # a temporary variable.
        $tmpImg = [System.Drawing.Image]::FromFile((Join-Path $PSScriptRoot 'demo.png')) 
        # Create an in-memory copy of the image. 
        New-Object System.Drawing.Bitmap $tmpImg
        # Dispose of the from-file image, which releases the file.
        $tmpImg.Dispose()
    }
    Location = New-Object System.Drawing.Point 10, 10
}))


# Add a button that will trigger the self-destruction
$btnSelfDestruct = New-Object system.Windows.Forms.Button -Property @{
    Text              = "Submit"
    Location          = New-Object System.Drawing.Point 160, 60
}
$form.Controls.Add($btnSelfDestruct)

# Add the button-click event handler.
$btnSelfDestruct.Add_Click({
    $form.Close()
    if ($SelfDestruct) {
        remove-OwnFolder
    }
    exit
})

# Show the form and wait for the use to close it.
$null = $form.ShowDialog()


来源:https://stackoverflow.com/questions/51919136/self-delete-folder-with-scripts-powershell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!