Enter-PSSession equivalent of $profile script - powershell

On my local PC and locally on the servers I admin, I regularly use the $profile script to set/output basic information. For instance running Set-Location to set the current path to the folder containing the scripts, and perhaps some Write-Host entries to show a basic cheat sheet for the most commonly used scripts and their expected parameters.
Does anyone know of a way to do something similar to that when using Enter-PSSession to connect interactively with a remote server?
As far as I can see there are no $profile files available with remote sessions, so I can't just add the commands in there (and the $profile used interactively on the local server doesn't get called when you remote into that same server).
Locally I've added functions to my local profile to make connecting to specific servers quicker, for example :
function foo{
$host.ui.RawUI.WindowTitle = "Foo"
Enter-PSSession -computername foo.local.mydomain.com -authentication credssp -credential mydomain\adminuser
}
and that works fine for connecting me (eg I type foo, then enter my password, and I'm in), but I still get dumped into C:\Users\adminuser\Documents.
I've tried adding things like the Set-Location command to the function after the connection, but that gets run in the local context (where the folder doesn't exist) and THEN it connects to the server. I even tried piping the commands to Enter-PSSession, but perhaps unsuprisingly that didn't work either.
Obviously things like Invoke-Command would allow me to specify commands to run once connected, but that wouldn't (as far as I can work out) leave me with an interactive session which is the primary aim.

You can't really automate unattended execution of anything that happens after Enter-PSSession connects your host to the remote session - but you can execute all the code you want in the remote session before calling Enter-PSSession:
function DumpMeInto {
param([string]$Path)
# Create remote session (you'll be prompted for credentials at this point)
$session = New-PSSession -ComputerName foo.local.mydomain.com -Authentication credssp -Credential mydomain\adminuser
# Run Set-Location in remote runspace
Invoke-Command -Session $session -ScriptBlock { Set-Location $args[0] } -ArgumentList $Path
# ... and then enter the session
Enter-PSSession -Session $session
}
Now you can do DumpMeInto C:\temp and it should drop you into a remote session on foo.local.mydomain.com with it's working directory set to c:\temp

Related

How to exit and remove Pssession without prompt for session number [duplicate]

On my local PC and locally on the servers I admin, I regularly use the $profile script to set/output basic information. For instance running Set-Location to set the current path to the folder containing the scripts, and perhaps some Write-Host entries to show a basic cheat sheet for the most commonly used scripts and their expected parameters.
Does anyone know of a way to do something similar to that when using Enter-PSSession to connect interactively with a remote server?
As far as I can see there are no $profile files available with remote sessions, so I can't just add the commands in there (and the $profile used interactively on the local server doesn't get called when you remote into that same server).
Locally I've added functions to my local profile to make connecting to specific servers quicker, for example :
function foo{
$host.ui.RawUI.WindowTitle = "Foo"
Enter-PSSession -computername foo.local.mydomain.com -authentication credssp -credential mydomain\adminuser
}
and that works fine for connecting me (eg I type foo, then enter my password, and I'm in), but I still get dumped into C:\Users\adminuser\Documents.
I've tried adding things like the Set-Location command to the function after the connection, but that gets run in the local context (where the folder doesn't exist) and THEN it connects to the server. I even tried piping the commands to Enter-PSSession, but perhaps unsuprisingly that didn't work either.
Obviously things like Invoke-Command would allow me to specify commands to run once connected, but that wouldn't (as far as I can work out) leave me with an interactive session which is the primary aim.
You can't really automate unattended execution of anything that happens after Enter-PSSession connects your host to the remote session - but you can execute all the code you want in the remote session before calling Enter-PSSession:
function DumpMeInto {
param([string]$Path)
# Create remote session (you'll be prompted for credentials at this point)
$session = New-PSSession -ComputerName foo.local.mydomain.com -Authentication credssp -Credential mydomain\adminuser
# Run Set-Location in remote runspace
Invoke-Command -Session $session -ScriptBlock { Set-Location $args[0] } -ArgumentList $Path
# ... and then enter the session
Enter-PSSession -Session $session
}
Now you can do DumpMeInto C:\temp and it should drop you into a remote session on foo.local.mydomain.com with it's working directory set to c:\temp

Powershell : I am trying to run a script on a remote server. The script is for gathering info of that remote and other servers in the same domain

Editing to be clear with the issue
I am running the below code from a local computer which should run the script Test.ps1 placed on $server at C:\Temp to collect data from $server and other servers.
When i perform this, the script runs but i only get data for the $server and not the others. While if i run the C:\Temp\Test.ps1 script sitting on the $server, i get the desired output for all servers.
I am using this code
$s = New-PSSession -ComputerName $server -Credential $credential
Invoke-Command -Session $s -Command {C:\Temp\Test.ps1}
I am getting the output for the remote server on which the code is placed (localhost for the script), buti am not getting any output for the other servers.
While if I run the script locally on the remote server i get output from all the servers
The script does not have to be on the remote host. PowerShell allows you to run local PS1 scripts on remote computers.
Running Remote Commands
https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7.1
Run a Script
To run a script on one or many remote computers, use the FilePath
parameter of the Invoke-Command cmdlet. The script must be on or
accessible to your local computer. The results are returned to your
local computer.
For example, the following command runs the DiskCollect.ps1 script on
the remote computers, Server01 and Server02.
Invoke-Command -ComputerName Server01, Server02 -FilePath 'c:\Scripts\DiskCollect.ps1'
As for this...
'My requirement is to run that script from the remote host per
security protocols'
... just use a script block as shown via the same MS Docs link
Run a Remote Command
To run a command on one or more computers, use the Invoke-Command
cmdlet. For example, to run a Get-UICulture command on the Server01
and Server02 remote computers, type:
Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {& .c:\Scripts\DiskCollect.ps1}
Of course, I just removed Get-UICulture cmdlet in the docs command, with a script to use.
It depends on how your remote script uses credentials to access other servers. This should classify as a double hop issue.
If you cannot use CredSPP, you can use Resource-Based Kerberos Constrained Delegation
or use credentials inside the Invoke-Command scriptblock i.e. you can define a credential object on the local computer to be used in the -credentials parameter, and refer to it with $using:cred in your scriptblock.
The article does a good job of summarizing all your options.

how to execute PowerShell commands from Windows server A so that it runs on Windows server B

Basically, i have PowerShell on both servers, is there a way to make a connection between both servers in such a way that when I run a command on PowerShell of Server A then it also runs on PowerShell of Server B.
I am new to PowerShell. Any help would be great.
You can use the New-PSSession-cmdlet in combination with the Invoke-Command-cmdlet
First of all create a remote session object:
$remoteSession = New-PSSession -ComputerName "YourComputerName" -Credential (Get-Credential)
Afterwards, you can use the $remoteSession object to execute commands on the remote via:
$servicesOnTheRemote = Invoke-Command -Session $remoteSession -Verbose -ScriptBlock { Get-Service * }
Invoke-Command runs Get-Service on the remote host, fetches the service state, serializes the data, and sends the data to the calling host. Based on that $servicesOnTheRemote includes the service state of the remote.
Also checkout this usefull cheatsheet.
Hope that helps.

Powershell Remoting: Load local script inside script

I launch a local script on a remote computer with:
Invoke-Command -ComputerName RemoteServer -FilePath C:\myFolder\Script1.ps1
This script dot-sources another script (Script2), which also is located on my local computer in "C:\myFolder". This fails because Script1 trys to load the Script2 from the remote computer.
Is there a way to load Script2 from my local computer inside Script1 inside the remoting session?
[Workaround]
Create a session to the remote server
Use the session to load the script2
use the same session to run the script1.
eg:- $Session = New-PSSession -ComputerName $Server
Invoke-command -Session $Session -FilePath <script2> this should load functions
Invoke-command -Session $Session -FilePath <script1>
here the functions in script2 will be available for script1 to consume, so no need to refer and dot source script2 .
I don't think this can work the way you outlined it since code running on the remote machine cannot find a file that is relative to the local machine.
The only way to achieve this is to share your script and include it as with a UNC path, or an administrative share, like \\localmachine\c$\users\test\script\a.ps1.
But there's a chance you'll run into authentication issues (double hop).
The (easiest) solution: copy all your scripts to the remote machine first and make sure that the paths used in the scripts will work.

Powershell PS Session script files with includes

So i'm trying to run a powershell script against a remote machine, using Enter-PSSession. I can connect and run a single script file and its contents no problem. However when i run this:
.\RemoteFile.ps1 "dev-web01" "builder" "test" "2.5.0.0" "Web" ".\stage_properties.xml"
As you can see there are 5 parameters to this script.
param (
[Parameter(Mandatory=$true)]
$Computername,
[Parameter(Mandatory=$true)]
$Username,
[Parameter(Mandatory=$true)]
$Password,
[Parameter(Mandatory=$true)]
$Version,
[Parameter(Mandatory=$true)]
$Packagenames,
[Parameter(Mandatory=$true)]
$Propfile
)
$securePassword = ConvertTo-SecureString -AsPlainText -Force $Password
$cred = New-Object System.Management.Automation.PSCredential $Username, $securePassword
Enter-PSSession -ComputerName $Computername -Credential $cred
Invoke-Command -ComputerName $Computername -Credential $cred -FilePath
.\DeploymentRun.ps1 -ArgumentList $Propfile -EnableNetworkAccess
When it gets to running the Invoke-Command with the $Propfile argument (stage_properties.xml) , it's looking on the remote machine since, i'm assuming the location context has changed, instead of the same local directory where RemoteFile.ps1 and DeploymentRun.ps1 reside. Here is the error I receive:
Cannot find path 'C:\User\builder\Documents\stage_properties.xml' because it does not exist.
How do i get around this? I've done a bit of searching, but can't seem to find a solution.
Any advice is greatly appreciated.
It is as you described; the the file name you're passing is a path relative to the local machine, so the code running on the remote machine cannot find a file in that path.
There isn't a way to get "around" it as you're just running code on the remote machine. The results are serialized and sent back to the calling client.
Your best bet is probably to send the file contents as a parameter instead of the file itself. Then of course the target script must be modified to deal with that.
You could also pass the path as a UNC path to a share on the local machine, perhaps even an administrative share, like \\localmachine\c$\users\builder\documents\stage_properties.xml. But there's a chance you'll run into authentication issues (double hop).
(Un)related question:
Why are you using Enter-PSSession and then using Invoke-Command?
Edit based on your comments:
First, if you want to make multiple calls in a single session to a remote machine, first create a PSSession:
$session = New-PSSession -ComputerName $ComputerName
Then use that session in all subsequent calls:
Invoke-Command -Session $session -File $filename
Invoke-Command -Session $session -ScriptBlock {
# Some code
}
Then close the session when you're done:
Remove-PSSession -Session $session
Note that Enter-PSSession is purely for interactive uses. You generally wouldn't use it inside a script. But it too takes a -Session parameter that can use a previously created session.
As to the issue of calling multiple files, you have a few pickles here. First, let's remember that when you call Invoke-Command with the -File parameter, it's the same as if you read the contents of the file yourself, made a script block out of it, and passed it to the script block.
All of those commands are executed on the remote side in the context of a process on the remote side. So if those scripts refer to any resources, including other scripts, modules, etc., those resources must be access from the context of the remote execution.
Based on that, you could in theory put all of these files on a share, accessible to both sides, and use UNC paths.
In practice, you have a different issue there: The so-called "double hop" authentication problem which prevents a remote machine from delegating your credentials. This means that once you've authenticated to the remote machine, you can't then pass off your credentials to a third machine (like a file server hosting a UNC share).
In most of the articles out there about this (including the one I linked) they'll talk about "enabling" multi-hop through the use of CredSSP. It's easy enough to enable CredSSP without fully understanding it. In my opinion, it's not a good solution generally; in most cases you want to re-think how you're doing things.
Back to this case:
If your script files didn't need to call or reference other script files, then you could easily just do multiple Invoke-Command calls, executing each one in sequence.
You touched upon a possible solution to your issue: copy all of the files to the target machine first. You just have to make sure that the paths used in the scripts will work (not an issue if you're passing it as a parameter!).
Another thing you can do: don't execute the code remotely! Just run it locally.
But I imagine that's not possible otherwise you wouldn't have tried remoting, so what you can do instead is create a scheduled task (or series of tasks) on the remote machine (they can be on-demand tasks only).
You could then reduce your remote calls to something like:
Invoke-Command -Session $session -ScriptBlock {
# PowerShell 3.0+
Start-ScheduledTask -TaskName 'My Special Task'
# Any version of PS
schtasks.exe /RUN /TN "My Special Task"
}