How can I make this Powershell script better

Ashley Levendelis 1 Reputation point
2022-05-17T15:02:42.26+00:00

Hi,

I'm new to Powershell scripting and I have made a simple script to move files from a downloads folder to other folders depending on file extension.
My script essentially does the same thing 4 times.

My question is, how can I write that script to be more effecient.

Thanks

Here it is:

Param (
[String]$Path
)

$ContainsTextFiles = $(Test-Path -Path $Path*.txt -PathType Leaf)
$ContainsMP3Files = $(Test-Path -Path $Path*mp3 -PathType Leaf )
$ContainsJPGFiles = $(Test-Path -Path $Path*.jpg -PathType Leaf)
$ContainsMP4Files = $(Test-Path -Path $Path*mp4 -PathType Leaf )

if ($ContainsTextFiles -eq $True) {
Move-Item -Path $Path*.txt -Destination C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\Documents\
Write-Host "All .txt files have been succesfully moved to .\Documents"
}Else{
Write-Error "No .txt files exist"
}

if ($ContainsMP3Files -eq $True) {
Move-Item -Path $Path*.mp3 -Destination C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\Music\
Write-Host "All .mp3 files have been succesfully moved to .\Music"
}Else{
Write-Error "No .mp3 files exist"
}

if ($ContainsJPGFiles -eq $True) {
Move-Item -Path $Path*.jpg -Destination C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\Pictures\
Write-Host "All .jpg files have been succesfully moved to .\Pictures"
}Else{
Write-Error "No .jpg files exist"
}

if ($ContainsMP4Files -eq $True) {
Move-Item -Path $Path*.mp4 -Destination C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\Videos\
Write-Host "All .mp4 files have been succesfully moved to .\Videos"
}Else{
Write-Error "No .mp4 files exist"
}

Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,346 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Rich Matheisen 44,621 Reputation points
    2022-05-17T18:51:14.023+00:00

    I guess that would depend on how you define efficiency! You script, as written, looks fairly efficient if a bit wordy.

    I'd start by eliminating the four lines of tests that load the values like "$ContainsTextFiles" and just do the Test-Path in the "if" conditional statements.

    To make it easier to add additional file types without adding a separate code block for each one, take the data values from, say a hash.

    See if this works. I haven't run it, but I don't think it contains any errors that would prevent it from running:

    [CmdletBinding()]  
    Param (  
        [ValidateScript({$_ -match "\\$"})]     # must end with a trailing "\"  
        [String]$Path  
    )  
      
    $Dest = "C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\"  
      
    $suffix = [ordered]@{  
        '.txt' = 'Documents'  
        '.mp3' = 'Music'  
        '.jpg' = 'Pictures'  
        '.mp4' = 'Videos'  
    }  
    $suffix.GetEnumerator()|  
        ForEach-Object{  
            $p = "{0}*{1}" -f $Path, $_.Key  
            if ( (Test-Path -Path $p -PathType Leaf) ) {  
                $d = "{0}{1}\" -f $Dest, $_.Value  
                Move-Item -Path $p -Destination $d  
                Write-Host "All $($_.Value) files have been succesfully moved to $Dest\$($_.Value)"  
            }  
            Else {  
                Write-Error "No $($_.Key) files exist"  
            }  
        }  
     
    
    0 comments No comments

  2. Rich Matheisen 44,621 Reputation points
    2022-05-18T02:17:38.98+00:00

    If you'd rather create a reusable function that wouldn't require modifying the code that does the actual moving of the files every time you want to move a different set of file types (or move the same set to a different subdirectory), you could do it this way:

    # Define the function
    Function MoveThem{
        [CmdletBinding()]
        Param (
            [Parameter(Mandatory=$true)]
            [ValidateScript({$_ -match "\\$"})]     # must end with a trailing "\"
            [String]$Path,
    
            [Parameter(Mandatory=$true)]
            [ValidateScript({$_ -match "\\$"})]     # must end with a trailing "\"
            [String]$Dest,
    
            [Parameter(Mandatory=$true)]
            [System.Collections.Specialized.IOrderedDictionary]$types
        )
    
        $suffix.GetEnumerator()|
            ForEach-Object{
                $p = "{0}*{1}" -f $Path, $_.Key
                if ( (Test-Path -Path $p -PathType Leaf) ) {
                    $d = "{0}{1}\" -f $Dest, $_.Value
                    Move-Item -Path $p -Destination $d
                    Write-Host "All $($_.Value) files have been succesfully moved to $Dest\$($_.Value)"
                }
                Else {
                    Write-Error "No $($_.Key) files exist"
                }
            }
    
    # use the function with a complete set of parameters
    $suffix = [ordered]@{
        '.txt' = 'Documents'
        '.mp3' = 'Music'
        '.jpg' = 'Pictures'
        '.mp4' = 'Videos'
    }
    $Dest = "C:\Users\Ashley\OneDrive\Documents\PowerShell\Project\"
    
    MoveThem -Path .\ -Dest $Dest $suffix
    
    0 comments No comments