Using Parameters when Calling Script with Start-Job - powershell

I am working on a script that must change users in the middle of running in order to be able to access a network folder. I have figured out how to get the credentials working, but now cannot understand how to pass parameters to the second script that is being called. The code that I currently have:
$myJob = Start-Job -ScriptBlock {& "\\my\folder\path\script.ps1" -serverName $serverName -serverInstance $serverInstance} -Credential $cred
$myJob | Wait-Job
$myJob | Receive-Job -Keep
I need to pass the serverName and serverInstance variables to the script that Start-Job is running, while also still being able to use credential. Is there a way to do this?
I have investigated Invoke-Command and Invoke-Expression, but neither of those fit this situation. Invoke-Command doesn't work with remote computers/drives and Invoke-Expression doesn't work with credentials. I tried the answer that was provided here, but that would not correctly pass in the parameters either.
Any help is much appreciated as I have been working on this problem for a few hours now. I am sure I am missing something obvious.

You can use the using scope modifier provided you are on PowerShell version 3 or higher:
$myJob = Start-Job -ScriptBlock {& "\\my\folder\path\script.ps1" -serverName $using:serverName -serverInstance $using:serverInstance}
You can also use local variables in remote commands, but you must indicate that the variable is defined in the local session. Beginning in Windows PowerShell 3.0, you can use the Using scope modifier to identify a local variable in a remote command. The syntax of Using is as follows:
$Using:<VariableName>
If you are on PowerShell version 2, you will need to utilize the -ArgumentList parameter and then modify your scriptblock to accept the arguments that are passed. Avshalom comments on one way to do this.
See About_Remote_Variables for more information.

Related

Powershell Invoke-Command passing environment variables

I wish to use Invoke-Command passing environment variables from the calling machine to the server where Invoke-Command is being executed.
I want this to work:
Invoke-Command -ComputerName MyServer-ScriptBlock {
$env:VAR=$using:env:USERNAME
Write-Host $env:VAR
}
But the output for this command is empty. If I do not use the $using scope modifier, and just assign the variable directly I get the expected output ("VAR").
Invoke-Command -ComputerName MyServer -ScriptBlock {
$env:VAR="VAR"
Write-Host $env:VAR
}
So, can I use $using with environment variables? If not, is there an easy way to pass environment variables over to the remote computer where Invoke-Command is running?
One option would be to assign the environment variable to a standard variable before invoking:
$username = $env:USERNAME
Invoke-Command -ComputerName MyServer-ScriptBlock {
$env:VAR=$using:userName
Write-Host $env:VAR
}
Note that assigning environment variables like this ($env:VAR=<value>) won't persist once your session ends. Use the Environment.SetEnvironmentVariable() method to do that.
I think you could use -ArgumentList. See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-6
Invoke-Command -ComputerName MyServer -ArgumentList $env:USERNAME -ScriptBlock {
Param ($x)
Write-Host $x
}
Update: The bug described below has been fixed in v7.3.
The existing answers show helpful workarounds.
It looks like you've hit a bug, present up to PowerShell 7.2.x:
The $using: scope - which is required for accessing variable values from the caller's scope in all out-of-runspace executions (see this answer) - should also support namespace variable notation (see this answer).
Thus, you should be able to pass a namespace-notation variable reference such as $env:USERNAME as $using:env:USERNAME:
indeed you can in the context of jobs (child-process-based background jobs started with Start-Job and thread-based jobs started with Start-ThreadJob); e.g.:
$env:FOO = 'bar'
# Outputs 'bar', as expected.
Start-Job { $using:env:FOO } | Receive-Job -Wait -AutoRemoveJob
but, as of PowerShell 7.1, that doesn't work with PowerShell remoting, such as Invoke-Command -ComputerName, as in your case.
The potential bug has been reported in GitHub issue #16019.

Powershell: How to pass parameter with invoke-command and -filepath remotely?

so there's a lot of similar topics to this I've found, but I can't find anything that correlates with my issue.
invoke-command -computername $serverLocation -Credential $cred -filepath "C:\path\script2.ps1" -ArgumentList $configPath
I am calling a for a script that is stored on my local machine to run on another server. Everything works as intended except for passing the "configPath" variable. This is how I initiate the script -
. .\script1.ps1 -serverLocation 'serverNameHere' -username 'userNameHere' -configPath 'configPathHere'
It correctly grabs all the other parameters I pass into the first script. It just won't pass the configPath to the second script in the 'filepath'.
How can I get this parameter to pass through? Thanks so much.
In script2.ps1, you should define a param() block that accepts the parameter, and then you can refer to it by whatever name you give it. If you don't want to use a param() block then using $args[0] should work.

Trouble passing parameters to a scriptblock

I am having alot of difficulty passing parameters to a script block in powershell.
$delScript={del C:\DateResults\* $args[0] $args[1] }
$result0 = Invoke-Command -ComputerName $targetServer.TrimStart("\\") -Credential $credentials -ScriptBlock $delScript -ArgumentList #("/q" , "/s")
I am starting to lose the plot trying to please the syntax hell of powershell and it's script block. I have researched this problem to death and I cannot even seem to get this basic problem working. I was hoping after spending the better part of 4hrs on this problem someone on SO could help me.
Thanks in advance!
You are having an issue since you are trying to run a old dos command that PowerShell created an alias for to help ease you into powershell. As mentioned in the comment del is an alias for Remove-Item. Remove-Item only accepts one positional argument which is -Path. To allow your script to work as is you should just be able change your $delScript to this
$delScript={cmd.exe /C del C:\DateResults\* $args[0] $args[1] }
Which would run your code the way you would expect. While I was typing this you already figured out the better approach which is to use the native Remove-Item and remove your -ArgumentList from Invoke-Command
$delScript={Remove-Item C:\DateResults\* -Recurse -Force}
I would also recommend you check Get-Alias to see other so you don't get yourself caught again.
Sorry, it was down to my own ignorance and stupidity. Hovering over 'del' in PowerGUI should have told me everything I needed to know.
Below is all I needed in the end.
$delScript={del C:\DateResults\* -Recurse -Force }
$result0 = Invoke-Command -ComputerName $targetServer.TrimStart("\\") -Credential $credentials -ScriptBlock $delScript

Powershell script using another user account

I'm not very good with powershell (to be honest, I'm bad !) but I need to do a script which download pictures and store them in a specific shared folder. I can download the pictures easily, but the folder where I need to store them is protected and there's is only one user (created specifically) who has access on it.
So my question is : how can I configure my script to use this user credentials ? I searched on the net, but I can't understand. As I said, I'm not a powershell user, and I use OS X at home, so I'm not even good with Windows rights and permissions. So a clear and easy answer would be really appreciated !
Thank's !
Use the Invoke-Command command with the -Credential and -ScriptBlock parameters to launch a PowerShell ScriptBlock as a different account. I believe that you will also need to enable PSRemoting in order for Invoke-Command command to work, even on the local system.
$Credential = Get-Credential;
$ScriptBlock = { Copy-Item -Path c:\test\test.txt -Destination c:\test2\test.txt; };
Invoke-Command -Credential $Credential -ScriptBlock $ScriptBlock;
A more complicated solution would be to use the Start-Process cmdlet with the -Credential parameter, to kick off an external executable under an alternate credential. If you just want to kick off PowerShell code though, you're better off using Invoke-Command.
$Credential = Get-Credential;
$Executable = 'c:\path\to\file.exe';
Start-Process -FilePath $Executable -Credential $Credential -Wait -NoNewWindow;

Call another powershell pass parameter use different creds

I want to call another secondary powershell script from within my primary powershell script. I want to pass it a parameter from the primary script, the secondary script needs the username parameter, I want to pass to it, from the primary, and then have the secondary script Im calling use different credentials. I think I might be able to use invoke-command, I just dont know all the syntax, anyone able to post some examples of what I want to accomplish, and then I'll fill in the blanks if need be?
Thanks in advance! :-)
Assume that your secondary script looks like this:
param (
[string] $Username = $args[0]
)
Write-Output -InputObject $Username;
You can use the Start-Process cmdlet to launch the script with alternate credentials.
$Credential = Get-Credential;
Start-Process -Wait -NoNewWindow -FilePath powershell.exe -ArgumentList '"c:\path\to my\file.ps1" -Username "UsernameGoesHere!"' -Credential $Credential;
Or you can use the Invoke-Command cmdlet:
Invoke-Command -FilePath 'c:\path\to my\script.ps1' -Credential $Credential -ArgumentList "UsernameGoesHere!";
I got it, thanks to Trevor Sullivan for pointing me in the right direction.
I ended up just putting my second ps1 file into a scriptblock, and running it as a job, and passing it the arguments from the main script, like this
$job = Start-Job -scriptblock {
param ($username)
some code to run against the variable that was passed in
} -Args $target -credential $Cred
$target being the variable I want to pass to my scriptblock
$username being the parameter that the scriptblock accepts
Thanks.