Improve controller script

howdy have basic menu to allow multiple selection of target functions see below.
pretty basic, more than likely not the correct way to set it out.

currently i have to enter the parameter variables for each script selected in the menu.

question 1 how do I pass the same variables to the corresponding variables in the target functions using Invoke-Expression $Choice? or is this not possible
parameter $computer
Parameter $credential
parameter $path

question 2 how do i set up the target functions to accept the variables.
currently those functions have the following parameters
parameter $computer
Parameter $credential
parameter $path

Function Get-MultiChoiceMenu{

begin{
    $Choices=@()
    [int]$ans -eq '0'
    Do{
        $Function = get-module PEToolkit -ListAvailable | %  {$_.ExportedCommands.Values} 
        $menu = @{}
        for ($i=1;$i -le $Function.count; $i++) 
        { Write-Host "$i. $($Function[$i-1].name),$($Function[$i-1].status)" 
        $menu.Add($i,($Function[$i-1].name))}

        [int]$ans = Read-Host 'Enter selection (Press "0" ) to quit'


        If([int]$ans -ne '0'){
            $menu.Item($ans)
            $Choices += $menu.Item($ans).Split(",")    
  
        } Else{
        
        }    

    } #End Do
    While ([int]$ans -ne '0')

}

Process{
    Foreach($Choice in $Choices){
            Invoke-Expression $Choice
            #pause
        }

}

Not sure what the end goal is here. Trying to write a wrapper to execute any cmdlet in a module and then pass parameters is going to be very difficult and a lot of code. Each cmdlet can have multiple parameter sets, so would need to pick a cmdlet, pick a parameter set and then prompt for parameters. Even in that, each parameter can be mandatory or optional. If you were trying to create a wrapper for a specific cmdlet or two with limited options, that is a bit more probable.

Try using splatting to pass common params:

$params = @{
    Name = 'WSearch'
}

Invoke-Command {Get-Service @params}

Hi @rob-simmers, thank you for your reply.
what I was hoping to do is…
audit a remote PC’s. the functions i use work individually using invoke-command -computername -credential -scriptblock etc.
I would like to lump them altogether and run
The intent is to point the controller script at txt file containing a list of Hostnames.

the plan…
have the controller script to select a group of functions, and pass the same parameters(hostname & credentials) each function requires as input to run.
Sort of enter once and use many if that makes sense

Currently, using a controller script, I can select a group of functions and run them consecutively.
However, i am prompted to enter the same parameters before for each function will run. I would like to automate this step

Entering parameters & passing the same parameters to a collection via the controller script, is what need to get my head around & understand.

Hopefully i have explained myself better this time
if it is not possible then so be it.

cheers
Peter

Can you provide a more specific example? Say you have a command for Get-Service and a command for Get-Process. You want to prompt for what commands or multiple commands and then have it execute with Invoke-Command against a list of computers? How would expect the output from those commands to be returned? One object returned? Try to provide an end to end example of the components and expected results.

Just throwing this out there. I wrote a computer audit script for local and remote systems. It contains approximately 40 audit items. It sounds like you intend to do something similar, but control the audit items as functions defined in a “controller script”. If I understand correctly, the controller script will contain a group of functions to execute on the systems. What I did was create an XML file that defines each item with a property of Enabled or Disabled. I would think you could do something similar with an XML file??

Just thinking out loud. Not entirely sure I understand your intent. Waiting to hear back on your answer to Rob’s question.

1 Like

Hi @rob-simmers & @tonyd, thankyou for your replies.
@tonyd unfortunately for me, I no very little about using xml files. so at my stage of development probably rules that out as i wouldn’t understand what is was doing.
I have uploaded a pic(screenDump) of what i do currently.
step 1 run the controller script which enumerates the functions in “toolkit.psm1”
step 2 choose the functions to run and exit that loop
step 3 exit controller script and run the functions as per screendump.


each function requires me to enter the computer name, credentials & output( in the example to screen). i am hoping there is a way to enter the parameters via the controller script and pass to the functions. I am sorry i’m not doing a very good job of explaining.

below is the line from the controller script that calls the functions using $Choice variable. Is there a way i can pass the parameters computer name, credentials from the controller script to the functions so they inherit those parameters, meaning i enter the parameters once, and they are passed to all the functions contained $Choice.

Process{
    Foreach($Choice in $Choices){
            Invoke-Expression $Choice
            pause
        }

Hmmm i’m not doing a very good job of this.

cheers Peter

Since it appears that the “controller script” is what needs to be changed, without seeing that code, I dont think you will get very much help here. From what I see, what you are doing can be totally automated, but we need to see the controller script to help with that.

@tonyd the controller script is at the very top of the post.

Sorry for my error. I completely misunderstood, what I get for skimming. My apology.

If I understand better now, it seems like what you are trying to do might be a bad idea. It seems that the functions in the module you reference will allow you to write your audit script. Simply create your script, import that module and write a script top down using the functions in the module where applicable.

@tonyd Hi Tony, thank you for your reply.
I shall give that a try.

Cheers,
Peter

Maybe this will get you started. COMPLETELY untested. If you create a file with a list of hosts separated by a comma, then adjust the path below, in theory, this should run all the functions in your module in the order they are listed one by one for each host. It also assumes the only arguments to each function are -ComputerName and -Credentials which is what you show in your screen shot.

$hosts = Get-Item 'C:\path\to\listofhosts.txt'
$creds = Get-Credential

begin{
	foreach($system in $hosts.Split(',')) {
		$Function = get-module PEToolkit -ListAvailable | %  {$_.ExportedCommands.Values} 
		for($i=1;$i -le $Function.count; $i++) { 
			Write-Host "$i. $($Function[$i-1].name),$($Function[$i-1].status)" 
			$menuitem = $Function[$i-1].name
			$cmdArg1 = "-ComputerName $system "
			$cmdArg2 = "-Credential $creds"
			$cmdToExec = "$($menuitem) $($cmdArg1)$($cmdArg2)"
			Invoke-Expression -Command $cmdToExec
		}
	}
}

Nice idea. :+1:t4:

Assumed the target computers are saved in a file each single one on a separate row shouldn’t something like this be enough then? :wink:

$ComputerNameList = Get-Content -Path 'C:\path\to\listofhosts.txt'
$creds            = Get-Credential
$FunctionList     = (Get-Module -Name PEToolkit ).ExportedCommands.Values.Name

foreach ($ComputerName in $ComputerNameList) {
    foreach ($Function in $FunctionList) {
        Invoke-Expression -Command "$Function -ComputerName $ComputerName -Credential $Cred"
    }
}

Looks good to me Olaf :slight_smile:

@Olaf @tonyd , hi boys I have had limited success with both options, which has everything to do with my lack of understanding, and I suspect they way i have constructed my functions. rather keep annoying everyone, I shall go away and play with the options you have provided. Hopefully, the light will come on eventually. thanks again for your help and suggestions. have a good one

cheers,
Peter

You can post error’s you are getting and there is no need to go away. However, without knowing much about the module you are dealing with, we can only do a best effort.

I was actually wondering how you want to catch the output of the different cmdlets. Usually different cmdlets provide different output. So you have to deal with it in different ways.

I wouldn’t go away. :wink: I would try again and again and harder. That’s how we all learn. You may consider another approach when the one just tried failed.