2

Someone kindly put together a powershell script for me. I'm a total amateur with programming. I haven't been able to reach this user to make a change that I'd like to to so I took it upon myself to modify the script myself.

Basically I want to pass an argument, two folder directories, so that the script can generate hash data from both source and destination and then compare them. The script works fine for that. But I want to check multiple sources and destinations.

I've done some googling and found that the following should work:

powershell.exe -Command 'C:\temp\hashcheck.ps1' -SourceDir "D:\Temp\Public" -DestDir "D:\Temp\Public2"

Where "sourcedir" and "destdir" are the names of the strings I want to pass. But when I run it from admin command prompt, it gives me error "unexpected token '-SourceDir'"

In the powershell script there are already a couple argument params but I added the "sourcedir" and "destdir" as follows:

            param (

                [Parameter(Mandatory=$True)]
                [String]
                $BaseDirectory,

                [Parameter(Mandatory=$True)]
                [String]
                $SourceDir,

                [Parameter(Mandatory=$True)]
                [String]
                $DestDir,

                [Parameter(Mandatory=$True)]
                [ValidateScript({!(Test-Path -path $_ -Type Leaf) })]
                [String]
                $OutputFilePath

            )

and then pass that argument on in these commands:

        # Run this for Source
        Get-TreeCheckSum -BaseDirectory "$SourceDir" -OutputFilePath C:\temp\PublicSource.xml -Verbose

        # Run this for Destination
        Get-TreeCheckSum -BaseDirectory "$DestDir" -OutputFilePath C:\temp\PublicDestination.xml -Verbose

Thanks for any help. It's probably a simple solution, but as I said, I am complete amateur with powershell. Thanks in advance.

EDIT: Here's the full code, maybe will make more sense. I basically want to pass the folder name under "# Run this for source" and "#Run this for Destination" section assigned to "BaseDirectory"

        # Created by P33500k for fun..
        # Use at your own risk follow directions at end to run the commands
        function Get-TreeCheckSum {
            [CmdletBinding()]
            param (

                [Parameter(Mandatory=$True)]
                [String]
                $BaseDirectory,

                [Parameter(Mandatory=$True)]
                [ValidateScript({!(Test-Path -path $_ -Type Leaf) })]
                [String]
                $OutputFilePath


            )

            begin {
                # Define $results as an array of objects
                $results = @()


            }

            process {
                Write-Verbose "Getting all files in $BaseDirectory..."
                # check files
                $allfiles = Get-ChildItem -path $BaseDirectory -Force -File -Recurse | select-object Name,FullName,Length

                Write-Verbose "Found $($allfiles.count) files in $BaseDirectory..."

                $n = 0
                Foreach ($File in $allfiles) {
                    $n++
                    Write-Progress -Activity "CheckSumming $BaseFolder" -Status "Checksumming $($File.FullName)" -PercentComplete (($n / ($allfiles | measure-object | Select-object -ExpandProperty Count)) * 100)
                    Write-Verbose "Checksumming $($file.fullname)"
                    $tempobj = New-Object -TypeName psobject -Property @{
                        'FullPath' = $file.FullName
                        'FileName' = $file.Name
                        'Size' = $file.Length
                        'Hash' = (Get-FileHash -Path $file.fullname | select-object -ExpandProperty Hash)
                        'RelativePath' = ($file.fullname.substring($BaseDirectory.Length))
                    }
                    $results += $tempobj
                    $tempobj = $null
                }
                Write-Verbose "Hashing Complete for file set in $BaseDirectory"

            }

            end {
                Write-Verbose "Writing Output File to $OutputFilePath"
                $results | Export-Clixml -Path $OutputFilePath
            }
        }

        # Run this for Source
        Get-TreeCheckSum -BaseDirectory "D:\Temp\Public" -OutputFilePath C:\temp\PublicSource.xml -Verbose

        # Run this for Destination
        Get-TreeCheckSum -BaseDirectory "D:\Temp\Public2" -OutputFilePath C:\temp\PublicDestination.xml -Verbose


        # Run this code for comparing

        # Global variables for comparing
        $Filesnotondestination = ".\FilesNotonDestination.txt"
        $Filesnotonsource = ".\FilesNotonSource.txt"
        $FailedHashes = ".\Failedchecksums.txt"

        $Source = import-clixml C:\temp\PublicSource.xml
        $Destination = import-clixml C:\temp\PublicDestination.xml

        Write-Host "Comparing objects.."
        $compare = Compare-Object -ReferenceObject $Source -DifferenceObject $Destination -Property RelativePath -IncludeEqual
        Write-Host "Writing file names to files only on source.."
        $compare | Where-object {$_.SideIndicator -eq "<="} | Select-object -expandproperty RelativePath | Set-content -path $Filesnotondestination
        Write-Host "Writing file names to files only on destination.."
        $compare | Where-object {$_.SideIndicator -eq "=>"} | Select-object -expandproperty RelativePath | Set-content -path $Filesnotonsource
        Write-Host "Comparing files on both source and destination... "
        $verify = $compare | Where-object {$_.SideIndicator -eq "=="}
        Write-Host "Found $($verify.count) files that are in both paths.." 
        $n = 0
        foreach ($v in $verify) {
            $n++
            Write-progress -Activity "Comparing file hashes.." -Status "Processing File: $($v.relativepath)" -PercentComplete (($n / ($verify | measure-object | Select-object -ExpandProperty Count)) * 100)
            #Write-Host "Comparing $($v.relativepath).."
            #Write-Host $v.relativepath
            Foreach ($s in $source) {
                If ($s.relativepath -eq $v.relativepath) {
                    $sourceh = $s.hash
                    #Write-Host "Source Hash: $Sourceh"
                }
            }
            Foreach ($d in $Destination) {
                If ($d.relativepath -eq $v.relativepath) {
                    $desth = $d.hash
                    #Write-Host "Destination Hash: $desth"
                }
            }
            If ($desth -eq $sourceh) {
                #Write-Host "File hashed match"
            }
            Else {
                Write-Warning "$($v.relativepath) - File Hashes Do Not Match"
                Add-content -path $FailedHashes -value "$(get-date) - $($v.relativepath) failed checksum: $sourceh not equal to $desth"
            }
        }

2 Answers 2

1

Try calling the script directly like this:

C:\temp\hashcheck.ps1 -SourceDir "D:\Temp\Public" -DestDir "D:\Temp\Public2"
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks epap. But for some reason it now wants to pass the parameter to 'BaseDirectory' for some reason...
1

You don't want to call the BaseDirectory parameter. So, change the source ps1 script into

Param (
  [string]$BaseDirectory,
  # The Rest of the script

It will not ask for base directory as it is no longer mandatory.

Now call the script with the rest parameters.

4 Comments

Thanks. Now when I run it, it prompts for SourceDir and DestDir, it doesn't pass the argument.
Please accept the answer by clicking the big grey tick mark and upvote it by the ^ looking button. Thank you for being helped.
Thanks for the help, but it still doesn't work. It asks for manual input of the argument "SourceDir" and "DestDir" even though I pass it with the -SourceDir and -DestDir. Any thoughts?
Anything marked mandatory, must be supplied. If you don't want to force the use of a defined param, then don't make it mandatory as Wasif Hasan's helpful answer shows. Remove all of these [Parameter(Mandatory=$True)].

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.