Tag Archives: Remove-Item

Self-Destruction Script

As a part of some work I’m doing, I’ve decided that I need a specific script to do some final configuration for me. More to come on that in time, perhaps. The point here, however, is that a PowerShell script completes my final configuration, and when this final configuration is complete, I have no need for my script any longer. Can a PowerShell script delete itself? Sure it can.

How does a script delete itself? Easy. It’s a single line, really. However, I have a mildly more interesting example. Before you take a look at the included gif — this really does lend itself to a visual — here are the contents of my self-destruction script. It echos an indication that the script will self-destruct. At this point, it begins a countdown in seconds, from 5 to 1, before removing itself — the script file — from the file system. Take a look, and maybe, just maybe, you’ll find yourself in need of something like this sometime, too.

Write-Output -InputObject 'This script will self-destruct in 5 seconds.'

5..1 | ForEach-Object {
    If ($_ -gt 1) {
        "$_ seconds"
    } Else {
        "$_ second"
    } # End If.
    Start-Sleep -Seconds 1
} # End ForEach-Object.

Write-Output -InputObject 'Self destruction.'

# Here's the command to delete itself.
Remove-Item -Path $MyInvocation.MyCommand.Source

And here’s, the visual representation. It’s a bit small, but you should be able to determine what’s happening. The script executes on the left, and once the countdown is over, DeleteSelfScript.ps1 is removed on the right. It’s deleted itself.

Enjoy the week, and learn something new!

Extract Media Folder from PowerPoint Files

On Wednesday, I wrote a response to something on Stack Overflow. So I don’t have to chase it down one day, I though I’d briefly discuss it here and include the updated code I would be more likely to use, providing I ever need to use it.

If you open a PowerPoint .pptx file in something like 7-Zip, you’ll quickly realize that the .pptx is a compressed, or archived, file format. While this brings down the file size (1.65MB file vs. 3.27MB when expanded), this is more more to say that there are a few folders, and several files, that make up a single PowerPoint file.

A person on Stack Overflow wanted to automate the expansion of a series of .pptx files and extract the media folder. This folder holds all the images in a PowerPoint file. I’m not going to bother to explain the code, but let me set the stage. I created a folder on my desktop called pptx. Inside the folder were four PowerPoint files using the .pptx file extension. My code created a new folder for each file in the pptx folder, expanded each PowerPoint file in their own new folders, located the nested media folder, moved it to the top level of their new folder, and then deleted all the other folders and files inside the new folder. If there wasn’t a media folder, it would still create the new folder; however, it would create a single text file in there called “No media folder.txt.” This was to help ensure the user didn’t think the code didn’t work, when they didn’t find the media folder inside the new folder.

I’ll included the original code from the forum post further below, but for now here’s an updated and cleaner version.

$Path = 'C:\users\tommymaynard\Desktop\pptx'
$Files = Get-ChildItem -Path $Path

Foreach ($File in $Files) {
    New-Item -Path $File.DirectoryName -ItemType Directory -Name $File.BaseName | Out-Null
    $NewFolder = $File.FullName.Split('.')[0]

    Add-Type -AssemblyName System.IO.Compression.FileSystem
    [System.IO.Compression.ZipFile]::ExtractToDirectory($File.FullName,$NewFolder)
    
    If (Test-Path -Path "$($NewFolder)\ppt\media") {
        Move-Item -Path "$($NewFolder)\ppt\media" -Destination $NewFolder
        Get-ChildItem -Path $NewFolder | Where-Object {$_.Name -ne 'media'} | Remove-Item -Recurse

    } Else {
        Get-ChildItem -Path $NewFolder | Remove-Item -Recurse
        New-Item -Path $NewFolder -ItemType File -Name 'No media folder.txt' | Out-Null
    }
}

And, here’s the original code and a link to the post itself. This below version didn’t use the $NewFolder variable, so there’s overwhelming inclusion of this piece of code: $File.FullName.Split(‘.’)[0]. It also defaulted to use the Expand-Archive cmdlet, if that was available. As I mentioned in the Stack Overflow post itself, it’s so slow. I’ve removed that so that it’s much faster now, which reminded me, I’ve actually written about this time difference before. It was just last October.

$Path = 'C:\users\tommymaynard\Desktop\pptx'
$Files = Get-ChildItem -Path $Path

Foreach ($File in $Files) {
    New-Item -Path $File.DirectoryName -ItemType Directory -Name $File.BaseName | Out-Null

    If (Get-Command -Name Expand-Archive) {
        Expand-Archive -Path $File.FullName -OutputPath $File.FullName.Split('.')[0]

    } Else {
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::ExtractToDirectory($File.FullName,$File.FullName.Split('.')[0])
    } # End If-Else.

    If (Test-Path -Path "$($File.FullName.Split('.')[0])\ppt\media") {
        Move-Item -Path "$($File.FullName.Split('.')[0])\ppt\media" -Destination $File.FullName.Split('.')[0]
        Get-ChildItem -Path $File.FullName.Split('.')[0] | Where-Object {$_.Name -ne 'media'} | Remove-Item -Recurse

    } Else {
        Get-ChildItem -Path $File.FullName.Split('.')[0] | Remove-Item -Recurse
        New-Item -Path $File.FullName.Split('.')[0] -ItemType File -Name 'No media folder.txt' | Out-Null
    } # End If-Else.
} # End Foreach.

Checking a Variable for a Path

I helped someone on a forum recently that needed to determine if a path existed or not. Providing the path did exist, they would need to perform an action. The problem wasn’t what to do (in the end), it was determining if the path existed (to begin with). Here’s a rough draft of their code:

$Path = 'C:\Scripts\TestFolder'

If ($Path) {
    Remove-Item -Path $Path
}

If you’ve been doing this a little while, then it’s quite easy to spot the problem with the “logic” used in the example above. The If statement’s condition is only evaluating if $Path has a value (if it contains something). The fact that the value may, or may not, be a path, and whether or not it exists (if it is a path), is not being evaluated. I recommended they use the Test-Path cmdlet, to ensure the value stored in $Path, was a path, and that it existed.

$Path = 'C:\Scripts\TestFolder'

If (Test-Path -Path $Path) {
    Remove-Item -Path $Path
}

There are times when all you will want to know is if a variable contains a value. As an example, we can use a variable to record if a specific process is running (at the time the variable is created), and take action depending on if it is, or isn’t.

The example below checks for a process called pn (Programmer’s Notepad) and stores the results in the $PNProcess variable. We can then check and determine if $PNProcess has been set, or assigned a value, and make a determination of what to do based on the results. Since we’re only looking to see if our variable contains a value, then this is a perfectly suitable solution.

$PNProcess = Get-Process -ProcessName pn -ErrorAction SilentlyContinue

If ($PNProcess) {
    Write-Output -Verbose "Programmer's Notepad is running."
} Else {
    Write-Output -Verbose "Programmer's Notepad is not running."
}

Note: While I would normally wrap a string in single quotes, double quotes are being used because single quotes will not work when there’s a single quote in the string.