Functions: How to create them for both local and remote uses? Script help!

Hey all,

First post here on Powershell.org. Hope I’m doing this right.

I’ve been learning PowerShell as much as I can (albeit slowly) and have finally started on functions. I knew it would come to this and although they are intimidating I’m ready to learn to stop repeating my code over and over! That being said, I was working on a script to uninstall an application when I attempted my first crack at a function and I immediately ran into a problem I couldn’t figure out.

What I’m trying to do: Create a simple function with one parameter (ComputerName) to uninstall a single application that is located at C:\Program Files\Fortify.exe. I would like the parameter to default to the local computer if none is specified. Within the function, a Test-Path would test C:\Program Files\Fortify.exe for the existence of an EXE to see if the app is already installed and, if not, write to the host.

All of that I have figured out (at least until you tell me I don’t lol), here is where I’m stuck: the paths need to change whenever the target switches from local to remote, right? For instance, if it’s a local uninstall (-ComputerName not specified) then the Test-Path would need C:\Program Files\Fortify.exe but if it’s a remote target it would need \$PC\C$\Program Files\Fortify.exe right? How do I implement that in a function? Any and all advice is much appreciated. Here is my code:

[pre]

function Uninstall-Fortify{

[CmdletBinding()]

Param(

[array]$ComputerName = $env:ComputerName

 

foreach ($PC in $ComputerName){

$ScriptBlock = {

Start-Process “C:\Program Files\Fortify.exe” -ArgumentList ‘–mode’,‘unattended’ -Wait

}

$filecheck = (Test-Path “C:\Program Files\Fortify.exe”)

$connectiontest = (Test-Connection -ComputerName $PC -Count 1 -Quiet)

 

if (($filecheck -eq $true) -and ($connectiontest -eq $true)){

Invoke-Command -ComputerName $PC -ScriptBlock $ScriptBlock

}else{

Write-Host “$PC is either not online or application does not exist.”

}

}

}

[/pre]

I have run into issues using the hostname when running a command on the localhost. I typically used ‘.’ instead when is less problematic.

[string[]]$ComputerName = '.'

Your second question around the test-path cmdlet can be solved by running it within the existing scriptblock.

$ScriptBlock = {
    if (Test-Path “C:\Program Files\Fortify.exe”) {
        Start-Process 'C:\Program Files\Fortify.exe' -ArgumentList '–mode','unattended' -Wait
    }
}

All together, something like this. I assume if the file fortify.exe isn’t present you do not need to uninstall it. You will likely want to add some try/catch blocks and any output you might want to track.

function Uninstall-Fortify {
    [CmdletBinding()]
    param(
        [string[]]
        $ComputerName = '.'
    )
    begin {
        $ScriptBlock = {
            if (Test-Path “C:\Program Files\Fortify.exe”) {
            Start-Process 'C:\Program Files\Fortify.exe' -ArgumentList '–mode','unattended' -Wait
            }
        }
    }
    process {
        foreach ($Computer in $ComputerName) {
            if (Test-Connection -ComputerName $Computer -Count 2 -Quiet) {
                Invoke-Command -ComputerName $Computer -ScriptBlock $ScriptBlock
            }
        }
    }
}

 

 

 

The function you build to work locally, you’ll want to run that function on a remote computer in the local context. It’s as if you walked over to the remote pc and ran the function locally. You’ll need to load the function into the session which you can do with dot sourcing, passing the function in the scriptblock, passing as an argument, etc. once you have it perfected for your local tests, we’ll be happy to help you run it remotely in an appropriate manner.

Ahhh, I see where I went wrong in multiple places. Mainly it seems I shouldn’t be trying to use \C$\ within a function at all. Don’t know why I didn’t see to move it into the Scriptblock and out of the Foreach but that’s why I post on forums! Thank you for taking the time to write that out, it’s super helpful to see someone write the same thing in a much more efficient way. I will work on the try\catch now and see what I can come up. The Write-Host was just a placeholder until this bigger problem was solved. Thanks again!

Since not all systems provide access to C$ remotely (unless configured to do so), adding to the scriptblock also alleviates this problem/check :slight_smile:

Hi

I found this article helpful in understanding how Running Functions Remotely :slight_smile:

https://powershell.one/code/12.html