Powershell variables in powershell direct...I'm confused
-
I tried a small variation from Cherokee's demo. I created a variable with this syntax
My expectation was that the variable I created would open a pssession instead of the results I received.
PS C:\WINDOWS\system32>$ps=new-pssession -vmname virt3datactr -credential virt3datactr\administrator
PS C:\WINDOWS\system32> $ps
Id Name ComputerName ComputerType State ConfigurationName Availability
1 WinRM1 Virt3datactr VirtualMachine Opened Available
When i used just the variable $ps i saw the above. Why didn't it open a pssession?
Then I did this...(changed the syntax NEW to ENTER)
PS C:\WINDOWS\system32> $ps=enter-pssession -vmname virt3datactr -credential virt3datactr\administrator (prompted for password)
[Virt3datactr]: PS C:\Users\Administrator\Documents> exit PS C:\WINDOWS\system32> $ps (expected C:\WINDOWS\system32>It didn't error, but it didn't show that it was in my virt3datactr pssession either.
-
John,
I hope all is well. Great initiative on your part !! You actually are on the right track, and in the right place, you just do not realize it :)
Let's see what we can do to clarify for you.
First, the New-PSSEssion cmdlet:
The New-PSSession cmdlet creates a PowerShell session (PSSession) on a local or remote computer. When you create a PSSession, PowerShell establishes a persistent connection to the remote computer.
Use a PSSession to run multiple commands that share data, such as a function or the value of a variable. To run commands in a PSSession, use the Invoke-Command cmdlet. To use the PSSession to interact directly with a remote computer, use the Enter-PSSession cmdlet.
You can run commands on a remote computer without creating a PSSession by using the ComputerName parameters of Enter-PSSession or Invoke-Command. When you use the ComputerName parameter, PowerShell creates a temporary connection that is used for the command and is then closed.
Second, the Enter-PSSession
cmdlet starts an interactive session with a single remote computer. During the session,the commands that you type run on the remote computer, just as if you were typing directly on the remote computer.
You can have only one interactive session at a time.When you switched to the Enter-PSSession cmdlet, you actually got the prompt that does show you are connected to your virt3datactr:
[Virt3datactr]:
PS C:\Users\Administrator\Documents> exit PS C:\WINDOWS\system32> $ps (expected C:\WINDOWS\system32>You were typing locally, but executing remotely BEFORE you issued the
exit PS
command. Once you did that, the prompt and session is focused back on the local machine you originated from.Hope that helps. :)
Cheers,
Adam
-
@Adam-Gordon I'm so sorry, but your answer makes absolutely no sense to me. Way too advanced. I am not a programmer by any means. I really struggle with powershell.
So ok I created a persistent connection. Shouldn't i see something like this? ([Virt3datactr]: PS C:\Users\Administrator\Documents>)
And I thought by exiting from the pssession I was closing the session.
What do you mean I was typing locally, but executing remotely...etc.
-
Hey @John-DeWilde ,
Your first command seems to have worked, maybe just not what you were expecting.
You created a variable, $ps. In this variable, you stored the command to create a new PSSession with virt3datactr. When you called the variable by name, it executed the command, and created a new PSSession, which is listed as ID 1 in the results of the command. You could verify this by running
Get-PSSession
. You should see the same results, listing the ID, Name, State, etc.However, your PowerShell prompt did not change, and this is where most people get confused. Creating a PSSession and entering a PSSession are not the same.
Once you have created the PSSession, you can execute commands in the session using the Invoke-Command cmdlet. The PSSession exists, but it is hiding in the background, waiting for you to use it.
$ps=new-pssession -vmname virt3datactr -credential virt3datactr\administrator Invoke-Command -Session $ps -ScriptBlock {Get-NetIPConfiguration}
This works great when you only need to execute a single command, or have a script you want to execute. It also works well when you need to execute the same command against several machines.
Once the scriptblock executes, you are returned to a local prompt. If you want to execute more commands against the remote machine, you will have to use the Invoke-Command cmdlet again. The PSSession is still there, it is persistent. But you have to call the session each time you want to use it.
The Enter-PSSession cmdlet starts an interactive session with a remote computer. The key difference is that word "interactive". Enter-PSSession creates a PSSession, and makes it active. It doesn't hide in the background. The PowerShell prompt changes, to indicate you are currently connected to a remote machine
[Virt3datactr]: PS C:\Users\Administrator\Documents>
. Now, all commands you typed are executed against the remote machine, without the need to use the Invoke-Command cmdlet.Enter-PSSession -vmname virt3datactr -credential virt3datactr\administrator [virt3datactr]PS C:> Get-NetIPConfiguration
Notice after the command completes, your prompt indicates you are still in an interactive session with the remote machine. You can continue to execute commands against the remote machine until you Exit-PSSession. This is very useful when you have several commands to execute, or need to run cmdlets that require interactivity (answering prompts, etc)
-
@Mike-Rodrick Sorry, I'm not getting this. I'm sure this is a long shot, but can you think of any existing courses I could fast forward through to try and get some further clarification?
-
Let me look and see...
-
This post is deleted!
-
@Mike-Rodrick I may have found some episodes. I was not use correct search terms
-
Cool. Let me know if you have more questions.
-
I found one of your lectures...microsoft-md100-3-2-2-configure-remote-connectivity-pt2
You're talking about what I'm trying get my head around, but I'm missing the basics. I'm not getting this stuff.
-
It's a confusing subject, it took me a while to grasp the differences 🤔 I think I will shoot a new video on the subject. The studios are down for upgrades right now, hopefully back online Friday. I will write up an outline today and post it for you. In the mean time, here is a link that will give you some more information.
I'll keep you posted,
-
Thank you Mike.
-
Mike what is the the difference between a session and a user session? I thought a pssession was a pssession. The link says anything in a "session" is temporary. This is a really confusing topic.
What Is a Session?
A session is an environment in which PowerShell runs.Each time you start PowerShell, a session is created for you, and you can run commands in the session. You can also add items to your session, such as modules and snap-ins, and you can create items, such as variables, functions, and aliases. These items exist only in the session and are deleted when the session ends.
And then there is this. One says temporary the other says it's not.
About Sessions
Technically, a session is an execution environment in which PowerShell runs. Each session includes an instance of the System.Management.Automation engine and a host program in which PowerShell runs. The host can be the familiar PowerShell console or another program that runs commands, such as Cmd.exe, or a program built to host PowerShell, such as Windows PowerShell Integrated Scripting Environment (ISE). From a Windows perspective, a session is a Windows process on the target computer.Each session is configured independently. It includes its own properties, its own execution policy, and its own profiles. The environment that exists when the session is created persists for its lifetime even if you change the environment on the computer. All sessions are created in a global scope, even sessions that you create in a script.
You can run only one command (or command pipeline) in a session at one time. A second command run synchronously (one at a time) waits up to four minutes for the first command to be completed. A second command run asynchronously (concurrently) fails.
And if I'm following a rabbit hole I shouldn't please tell me. It just seems relevant to the pssessions
-
Good questions, definitely relevant to understanding the concepts.
Lets start with the definition of a session. Microsoft says
A session is an environment in which PowerShell runs.
When you launch PowerShell, like any other application, it needs certain things to function. Memory space, access to the processor, access to the hard drive, access to the network, the code for PowerShell itself, etc. All of this together is the "environment". Kind of like a box, containing PowerShell and all the stuff necessary for PowerShell to function.
Now, the confusing part. There are three types of sessions: the default session, PSSessions, and temporary sessions.
Default Session
When you launch PowerShell, a session is created. PowerShell is loaded, and assigned memory, etc. This is the default session. MIcrosoft docs defines the default session as:
Each time you start PowerShell, a session is created for you, and you can run commands in the session. You can also add items to your session, such as modules and snap-ins, and you can create items, such as variables, functions, and aliases. These items exist only in the session and are deleted when the session ends.
In other words, anything you create or add while running PowerShell is deleted when you close PowerShell.
Try this:
- Launch PowerShell (you now have a default session)
- Type the following
$h = hostname
and hit enter (you have created a variable in your session) - Then type
$h
and hit enter - It should return the name of your computer. (you can use the variable while in the session)
- Now close PowerShell (you have ended your session, and all items created are deleted)
- Launch PowerShell again (this is a new default session)
- Type
$h
and hit enter (you wont get anything back, the variable doesn't exist in this session) - Close PowerShell
I'm going to try a new analogy so bear with me. This might not work, lol.
Think of the default session as a company car. You can use it, but you didn't get to pick the model or color. You can put your stuff in it, your fuzzy dice on the rear view mirror, your roller-bead back massager, etc. But when you are done, you have to remove all of your stuff. When you use it again, you will have to add all your stuff again.
This is how the default session works. You can launch PowerShell. You can add to it. But you cannot control the default session. When you end the session, anything you added is gone, and will need to be added again. This is why we modify our PowerShell profile. So I can automatically add things I know I need every time PowerShell starts.
PSSessions
PSSessions are also known as "PowerShell sessions" or "user-managed sessions" From Microsoft docs:
Like the default session, you can run commands in a PSSession and add and create items. However, unlike the session that starts automatically, you can control the PSSessions that you create. You can get, create, configure, and remove them, disconnect and reconnect to them, and run multiple commands in the same PSSession. The PSSession remains available until you delete it or it times out.
PSSessions are typically used to run commands on remote computers. If I need to run a PowerShell command on a remote server, I have a couple of choices. I could use remote desktop to connect to the server. Then I could just launch PowerShell (a default session). But if I don't want the overhead of establishing a RDP connection (maybe I don't have RDP permissions, time consuming, etc), I could use a PSSession. You are still connecting to the remote computer over the network, but instead of connecting to the entire desktop, you are only connecting to PowerShell.
When you use
New-PSSession
you are creating a PowerShell session on the remote computer. You can then connect to that session and enter commands. You can disconnect from the session, but it is still running on the remote computer. You can reconnect to the session and continue to execute commands. Read that again, those last couple of statements are important. This is where we start using the word persistent.Lets say you needed to start a long-running process on a remote machine. You would launch PowerShell on your local machine (default session). Then you could create a PSSession with the remote machine. You could then enter commands in the PSSession (using Invoke-Command). Then you would disconnect from the PSSession (Disconnect-PSSession) The session (and the long running process) are still going on the remote computer, you are just not connected to it. Later in the afternoon, you would reconnect to the PSSession (Connect-PSSession) to check on the status of the long-running process. This is what they mean by persistent. Until you end the PSSession (Remove-PSSession) the session is still there, and anything you added or created, even if you disconnect from the session.
Another confusing aspect at this point, when you use New-PSSession, it creates the session on the remote computer, but you don't automatically connect to it. Normally you store the connection in a variable, and then use it in an Invoke-Command cmdlet. This is why your prompt doesn't change. More on that in a minute.
Lets try the car analogy again. Think of a PSSession as your personal car. You can pick the model and the color. (You control the session). You can add your stuff to it, fuzzy dice, bumper stickers, etc (variables, functions, etc) You can park it in your garage and go inside. (You are disconnected) When you go to your car later (reconnect) your fuzzy dice and bumper stickers are still there (persistent) They will be there until you sell the car (remove the session). If you buy a new car (create a new PSSession) you will have to add your stuff again. (so persistent for the life of the session, but temporary because they don't transfer to new sessions)
Try this:
- Open PowerShell (creating a default session on the local machine)
- Type
$s = New-PSSession -ComputerName svr01
(substitute the name of you remote computer) - Type
$s
(you will see the PSSession stored in the variable $s, note the name of the session for later) - Type
Invoke-Command -Session $s -ScriptBlock {$h = hostname}
(you are executing the command hostname against the remote computer, and storing the results in the variable $h) - Type
$h
(you get nothing back, because the variable is in the PSSession, not the default session) - Type
Invoke-Command -Session $s -ScriptBlock {$h}
(it should return the name of the remote computer) - Type
Disconnect-PSSession -Name '*session name noted earlier*'
(you have disconnected from the session, but it is still active on the remote machine) - Close PowerShell (end the default session)
- Launch PowerShell (create a new default session)
- Type
Get-PSSession -ComputerName svr01
(substitute the name of you remote computer. You will see the PSSession still exists on the remote computer, but the state is disconnected$s) - Type
$s = Connect-PSSession -ComputerName svr01 -Name session2
(using your computer and session names.) - Type
$s
You will see the session state is now opened, meaning connected and available) You have reconnected to a persistent PSSession on the remote computer. - Type
Invoke-Command -Session $s -ScriptBlock {$h}
(it should return the name of the remote computer, because the variable is persistent, or still exists in the PSSession) - Type
Remove-PSSession -Name session2
(using your session name. This disconnects and ends the PSSession on the remote computer) - Type
Get-PSSession -ComputerName svr01
(substitute the name of you remote computer. The session, and any variables created, etc are deleted)
Temporary sessions
There are two ways to create temporary sessions. You can use the Invoke-Command cmdlet with the -ComputerName parameter (not the -Session parameter), or you can use the Enter-PSSSession cmdlet.
If you use the Invoke-Command method, PowerShell creates a temporary session with the remote computer, executes the command, and then removes the temporary session. One and done.
Try this:
- Type
Invoke-Command -ComputerName svr01 -ScriptBlock {ipconfig}
(returns the IP info for the remote computer) Really useful for running a simple, single command.
Then try what we did earlier:
- Type ```Invoke-Command -ComputerName svr01 -ScriptBlock {$h = hostname}``
- Type
Invoke-Command -ComputerName svr01 -ScriptBlock {$h}
Nothing is returned, because the variable $h was deleted as soon as the first command completes. No persistence.
If you use the Enter-PSSession cmdlet, PowerShell creates a temporary interactive session. Your prompt will change to indicate that anything you type will be executed on the remote machine. This temporary session will last until you Exit-PSSession. You will have persistence for the life of the temporary session.
Try this:
- Type
Enter-PSSession -ComputerName svr01
(your prompt will change to indicate the connection) - Type
$h = hostname
- Type
$h
(should return the name of the remote computer. The variable is persistent for the life of the temporary session) - Type
Exit-PSSession
(Ends the temporary session) - Type
$h
(Nothing returned, the variable has been deleted) - Type
Enter-PSSession -ComputerName svr01
(create a new temporary session) - Type
$h
(Nothing returned, the variable was indeed deleted) - Type
Exit-PSSession
(Ends the temporary session) - Close PowerShell
Another point of confusion. The PowerShell cmdlets use the term PSSession for both PSSessions and temporary sessions. 🤦♂️
Back to the car analogy. Temporary sessions are like rental cars. You can get one when you need it. You can use it and even add stuff to it. But you have to turn it in. If you leave and stuff in there, its gone (probably, lol) If you need it again, you'll probably get a different car, and have to add your stuff again.
OK, This might be a record for longest post. I'll stop for now. Let me know if this helps clear things up (and if the car analogy worked, lol) And ask more questions if not!
-
Wow, thank you for the all the information. Unfortunately, I can't execute the cmdlet Type $s = New-PSSession -ComputerName svr01. The remote machine is a server in a workgroup with access to the internet. When I execute $s = New-PSSession -ComputerName svr01 (with my server name of virt4datactr) I receive (I tried the cmdlet with a connection made to the remote machine and without. Both failed)
atactr
-
~~
- CategoryInfo : InvalidData: (:) [Get-Content], ParameterBindingValidationException
- FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentCommand
Googling isn't giving me anything that is helpful.
I did replace -ComputerName with -VmName and it worked. Is that keeping in the spirit of the explanation?
PS C:\WINDOWS\system32> $s = New-PSSession -vmname virt3datactr
cmdlet New-PSSession at command pipeline position 1
Supply values for the following parameters:
Credential
PS C:\WINDOWS\system32> -
-
Type Invoke-Command -Session $s -ScriptBlock {$h = hostname} (you are executing the command hostname against the remote computer, and storing the results in the variable $h)
Type $h (you get nothing back, because the variable is in the PSSession, not the default session)
Could you clarify these statements? I don't understand.And,
When I try running the disconnect cmdlet, it doesn't work. These are my resultsPS C:\WINDOWS\system32> Disconnect-PSSession -Name virt3datactr
Disconnect-PSSession : The remote session with the name virt3datactr is not available.
At line:1 char:1- Disconnect-PSSession -Name virt3datactr
-
+ CategoryInfo : InvalidArgument: (virt3datactr:String) [Disconnect-PSSession], ArgumentException + FullyQualifiedErrorId : RemoteRunspaceNotAvailableForSpecifiedName,Microsoft.PowerShell.Commands.DisconnectPSSessionCommand
I also tried using the variable name $S, and it didn't error out. Didn't disconnect either shows open and available.
So I'm moving from really confused to totally lost in this.
PS C:\WINDOWS\system32> Disconnect-PSSession -Name $s
PS C:\WINDOWS\system32> get-pssessionId Name ComputerName ComputerType State ConfigurationName Availability
4 WinRM4 Virt3datactr VirtualMachine Opened Available
I'm having a hard time putting this all together, but I really am thankful for your time on this.
-
@Mike-Rodrick said in Powershell variables in powershell direct...I'm confused:
Then try what we did earlier:
Type ```Invoke-Command -ComputerName svr01 -ScriptBlock {$h = hostname}``
Type Invoke-Command -ComputerName svr01 -ScriptBlock {$h}Nothing is returned, because the variable $h was deleted as soon as the first command completes. No persistence.
I'm lost again. Why is the variable deleted? I know you're saying no persistence, but I'm not following.
As long as the powershell session is running the variable should work...in my mind..
-
And if i invoke or enter a pssession is that a temporary session within my default/temporary powershell session or is it a "pssession" on my remote machine? Another thing not making sense is the deletion of the variable $h. Why wouldn't that last as long as the powershell session is running even if the pssession is closed.
If you use the Enter-PSSession cmdlet, PowerShell creates a temporary interactive session. Your prompt will change to indicate that anything you type will be executed on the remote machine. This temporary session will last until you Exit-PSSession. You will have persistence for the life of the temporary session.
Try this:
Type Enter-PSSession -ComputerName svr01 (your prompt will change to indicate the connection)
Type $h = hostname
Type $h (should return the name of the remote computer. The variable is persistent for the life of the temporary session)
Type Exit-PSSession (Ends the temporary session)
Type $h (Nothing returned, the variable has been deleted)
Type Enter-PSSession -ComputerName svr01 (create a new temporary session)
Type $h (Nothing returned, the variable was indeed deleted)
Type Exit-PSSession (Ends the temporary session)
Close PowerShellAre you sure you really meant for me to ask questions??