How to invoke Powershell version 2 on remote computer via Invoke-Command - powershell

I'm trying to remotely setup websites on web servers using powershell. The web servers I'm attempting to configure are Windows Server 2008 R2 SP1 which has powershell v2 on it by default.
To make things easier, I'm using the Snapin "WebAdministration".
Whenever I attempt to invoke a the following command:
PS C:\p4\eacp4wireframe\ReleaseEngineering\DL_Powershell\Infrastructure\PowerShell\IIS> Invoke-Command -ComputerName web4 -Credential $admin -ScriptBlock {add-pssnapin WebAdministration; Get-Website}
No snap-ins have been registered for Windows PowerShell version 2.
+ CategoryInfo : InvalidArgument: (WebAdministration:String) [Add-PSSnapin], PSArgumentException
+ FullyQualifiedErrorId : AddPSSnapInRead,Microsoft.PowerShell.Commands.AddPSSnapinCommand
I get the dreaded "No snap-ins have been registered for Windows PowerShell version 2" error.
Logically, I check the version of powershell by running this command:
PS C:\ Invoke-Command -ComputerName web4 -Credential $admin -ScriptBlock {(Get-Host).version}
Major Minor Build Revision PSComputerName
----- ----- ----- -------- --------------
1 0 0 0 web4
I can remotely login to the web server and run the Powershell commands fine.
Any ideas?

That version number is the version number of the host implementation used by remoting e.g.:
C:\PS> Invoke-Command . {Get-Host | Get-Member}
TypeName: System.Management.Automation.Internal.Host.InternalHost
You have to be using at least the PowerShell 2.0 engine because that is when PowerShell Remoting was introduced. It is more likely that you're invoking the 64-bit PowerShell remoting endpoint and you have snapins that either haven't been registered for the 64-bit PowerShell or won't run in 64-bit PowerShell (or vice versa).
If you need to invoke the 32-bit remoting endpoint try this:
C:\PS> Invoke-Command . {[intptr]::size} -ConfigurationName Microsoft.PowerShell32
4

Related

Powershell Direct from Jenkins to Hyper-v Windows 10

I have been trying to use Jenkins to automatically test VMs, which includes copying new code into the VM, or running certain commands from the host into the VM using Powershell Scripts.
However, I've been running into an error trying to using "Invoke-Command" or "New-PSSession" to a hyper-V Windows 10 VM in Jenkins Freestyle and Pipeline projects.
This is the environment Jenkins is running on:
Windows Specifications:
Edition: Windows Server 2019 Standard
Version: 1809
OS build: 17763.379
Jenkins ver. 2.190.1
Hyper-V Manager: 10.0.17763.1
This is the Powershell Scripts that I've written in a "Windows Powershell" Build Step in a freestyle project:
# Win10-Clean is currently running and the credentials are for the Win 10 VM.
$ErrorActionPreference = "Stop"
$VMName = "Win10-Clean"
$username = "username"
$pwd = "password"
$secpasswd = ConvertTo-SecureString $pwd -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("$username", $secpasswd)
Get-VM
Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}
I expect the output to be:
Running as SYSTEM
Building on master in workspace G:\ci_server_1\jenkins\workspace\powershell-testing-ground
[powershell-testing-ground] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Windows\TEMP\jenkins6936256398230803297.ps1'"
Name State CPUUsage(%) MemoryAssigned(M) Uptime Status Version
---- ----- ----------- ----------------- ------ ------ -------
Win10-Clean Running 0 1854 5.14:10:42.5100000 Operating normally 8.3
PSComputerName : Win10-Clean
RunspaceId : 56151e46-5772-458f-8f11-9beba5491bc2
Name : ServerRemoteHost
Version : 1.0.0.0
InstanceId : fe09fc40-8434-4a7c-903b-b7b2c3f88506
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : en-US
CurrentUICulture : en-US
PrivateData :
DebuggerEnabled : True
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
Finished: SUCCESS
But what I got was this:
Running as SYSTEM
Building on master in workspace G:\ci_server_1\jenkins\workspace\powershell-testing-ground
[powershell-testing-ground] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Windows\TEMP\jenkins233354859509300046.ps1'"
An error has occurred which Windows PowerShell cannot handle. A remote session might have ended.
At C:\Windows\TEMP\jenkins233354859509300046.ps1:7 char:1
+ Invoke-Command -Credential $mycreds -VMName Build_VM -ScriptBlock {ho ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (Build_VM:String) [], PSRemotingDataStructureException
+ FullyQualifiedErrorId : PSSessionStateBroken
Build step 'Windows PowerShell' marked build as failure
Finished: FAILURE
After referring to the official microsoft web page regrding this issue, the possible causes are:
VM exists but not running
Guest OS does not support PowerShell Direct
Powershell isn;t avaliable in the guest yet:
Operation system hasn't booted yet
OS can't boot correctly
Some boot time event needs user input
A bug in current builds where credentials must be explicitly passed with -Credential. Run Restart-Service -Name vmicvmsession as a work around.
However, from the output from Jenkins, the VM that I've been trying to connect to is "Running" and it is booted up properly.
Then, I've tried to "Invoke-Command" and "New-PSSession" into the VM from the host directly and I am able to connect to the VM.
I've also tried the same thing in a Jenkins installed in a Windows 10 machine instead of a windows server 2019 and everything works.
As for the user administrative information, the user logged in that is running Jenkins is both the "administrator" and the "hyper-v administrator".
These are some of the references I used to debug and I'm not able to find out what the problem is:
Remote Access With PowerShell and Jenkins, but I'm not able to figure out how exactly this works.
Running Powershell scripts using Jenkins
PowerShell: error executing command using Invoke-Command?
EDITS:
I found a way around this issue. Please mind that this isn't the definite solution but a work around.
Instead of running Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}, run this:
Invoke-Command -ComputerName "MyHostComputer" -ScriptBlock {Invoke-Command -Credential $mycreds -VMName $VMName -ScriptBlock {host}}
This command is essentially invoke-commanding into the host machine and use the host machine to run the Invoke-Command into the VM.
It is definitely not the perfect solution, but before anyone has a better solution I'll go with this for now.

Hyper-V Script Won't Recognize Remote Virtual Machines

I am creating a PowerShell script to be run as a scheduled task. It's purpose is to create a snapshot on each of our virtual machines every Monday. I've created a short script for each VM. After establishing a remote session to our local Hyper-V server, it should simply find our virtual machine and create a Snapshot. This is what it looks like when testing:
PS C:\Users\crhoden\Documents\Scripts\HyperV Snapshot Job> .\win7
Name State CPUUsage(%) MemoryAssigned(M) Uptime Status Version
---- ----- ----------- ----------------- ------ ------ -------
Windows 10 Professional Off 0 0 00:00:00 Operating normally 7.0
Windows 7 Professional Pre-Alpha Saved 0 0 00:00:00 Operating normally 7.0
Windows 8.1 Professional Pre-Alpha Off 0 0 00:00:00 Operating normally 7.0
Windows Server 2012 R2 Off 0 0 00:00:00 Operating normally 7.0
Get-VMSnapshot : Hyper-V was unable to find a virtual machine with name "Windows 7 Pro".
At C:\Users\crhoden\Documents\Scripts\HyperV Snapshot Job\Win7.ps1:6 char:1
+ Get-VMSnapshot -VMName $vmname | Where-Object {$_.CreationTime -lt (G ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-VMSnapshot], VirtualizationException
+ FullyQualifiedErrorId : ObjectNotFound,Microsoft.HyperV.PowerShell.Commands.GetVMSnapshot
Checkpoint-VM : Hyper-V was unable to find a virtual machine with name "Windows 7 Pro".
At C:\Users\crhoden\Documents\Scripts\HyperV Snapshot Job\Win7.ps1:7 char:1
+ Checkpoint-VM -Name $vmname -SnapshotName "Weekly Snapshot $((Get-Dat ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Checkpoint-VM], VirtualizationException
+ FullyQualifiedErrorId : ObjectNotFound,Microsoft.HyperV.PowerShell.Commands.CheckpointVM
[hypervserver]: PS C:\Users\crhoden\Documents> get-vm
Name State CPUUsage(%) MemoryAssigned(M) Uptime Status
---- ----- ----------- ----------------- ------ ------
Windows 10 Pro Running 1 1172 1.00:49:27 Operating normally
Windows 7 Pro Running 0 1024 10:54:07 Operating normally
Windows 8 Pro Running 0 1159 16.22:02:43 Operating normally
Windows 8.1 Pro Running 1 1716 16.21:43:03 Operating normally
[hypervserver]: PS C:\Users\crhoden\Documents>
As you can probably tell, when I manually run a "get-vm", the remote machines turn up just fine. But when ran as a script, it still searches my workstation instead. Here are the contents of the script:
Enter-pssession -computername hypervserver
start-sleep -s 10
cd C:\
$vmname = 'Windows 7 Pro'
get-vm
Get-VMSnapshot -VMName $vmname | Where-Object {$_.CreationTime -lt (Get-Date).AddDays(-15) } | Remove-VMSnapshot
Checkpoint-VM -Name $vmname -SnapshotName "Weekly Snapshot $((Get-Date).toshortdatestring())"
I added the start-sleep command as an attempted fix, thinking commands were firing before the connection was established. No such luck. The kicker is if I run through this script line by line, it works just fine. Any help is appreciated. EDIT: It also works perfect when pasting in the contents of the script in their entirety.
Enter-PSSession is for interactive sessions only, so working interactively or pasting into a session does work, but not in a script which is by nature not interactive.
You can either
execute the script remotely or
use the -ComputerName parameter of Get-VMSnapShot
As you discovered by yourself the used cmdlet has to match the Hyper-Vserver version.

Run remote Powershell session as version 2

I'm on a server that is running Powershell Version 2:
PS C:\> $PSVersionTable
Name Value
---- -----
...
PSVersion 2.0
I then create a new remote session to a different computer and connect to it:
$sess = New-PSSession -ComputerName {ComputerName} -Credential $credential
It returns me the result:
PS C:\> Invoke-Command -Session $sess -ScriptBlock { $PSVersionTable }
Name Value
---- -----
...
PSVersion 3.0
However, I need Powershell to be in Version 2 for my script so I enter a session (to make it easier). I then try to get Powershell to be Version 2:
C:\> Enter-PSSession -Session $sess
[{ComputerName}]: PS C:\> Powershell -Version 2
Windows Powershell
Copyright (C) 2009 Microsoft Corporation. All rights reserverd
And then it just hangs (or at least never lets me enter anything else into the console until I Ctrl-C).
I've also tried going through the Invoke-Command:
PS C:\> Invoke-Command -Session $sess -ScriptBlock { Powershell -version 2 }
and it does the same.
I've also tried to register a PSSessionConfiguration as per here: https://technet.microsoft.com/en-us/library/hh847899.aspx
PS C:\> Register-PSSessionConfiguration -Name PS2 -PSVersion 2.0
But I get:
Register-PSSessionConfiguration: a parameter cannot be found that matches parameter name 'PSVersion'.
Does anyone have any ideas of what I can try next?!
Thanks
On what machine did you run Register-PSSessionConfiguration?. Your computer or the "server"?
You need to make the configuration on the target server. That is what you will be running the hosted PSSessionConfiguration.
I just tried the steps in the technet article and it worked perfectly. My 2008 server remoted to my windows 7 machine running a 2.0 PSSessionConfiguration.
On target server/host:
Register-PSSessionConfiguration -Name PS2 -PSVersion 2.0
Then, on the client machine, reference the 'PS2' configuration.
$s = New-PSSession -ComputerName Server01 -ConfigurationName PS2
I take it that the following doesn't work either:
#Requires -version 2.0
Another kluge you could try is to create a scheduled task on the target and have the task fire off your script with Powershell.exe -version 2

Is it possible to start a process as "nt authority\system" over Powershell remoting?

I'm automating the testing of the installation, detection, and uninstallation of some Windows applications. In order to run most of those installers silently, they must be run as nt authority\system. That is easy enough to accomplish on a local machine by invoking psexec something like this:
psexec -s setup.exe /S
I need to be able to automatically roll back the test target computer to known-good states, so I'm using another computer to orchestrate all this. Ideally I could use PowerShell remoting to start the installer on the target computer. I haven't yet found a way to achieve that.
Attempt 1: psexec from a Remote Session
The most obvious thing to do is to connect to the target computer using remoting and invoke psexec -s. Here's what that looks like:
[target.ad.example.com]: PS C:\Users\un1\Documents> C:\PsTools\PsExec.exe -s whoami
C:\PsTools\PsExec.exe :
+ CategoryInfo : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
The problem is, the process just hangs at that point.
Attempt 2: Start-Process with -Verb RunAs
Using the RunAs verb with Start-Process may well run a process elevated, but it doesn't seem to run it as nt authority\system:
whoami-to-file.bat
whoami > out.txt
PowerShell Session
[target.ad.example.com]: PS C:\> Start-Process .\whoami-to-file.bat -Verb RunAs -WorkingDirectory
[target.ad.example.com]: PS C:\> Get-Contents out.txt
example\un1
The process is not started as nt authority\system.
The Question
Is it possible to start a process as nt authority\system over PowerShell remoting? If so, how?
Note: I'm no expert at Windows security and credentials, so I don't understand the exact security implications of this technique. In my case the only credentials in question are those a temporary test computer, so there isn't much risk. I doubt this technique is a good idea for production.
It's a Double-Hop (I think)
clymb3r's article about CredSSP I think explains why psexec -s fails over PowerShell remoting. I think that PowerShell remoting counts as one hop and invoking psexec -s counts as a second hop. If that's the case we have a manifestation of the double-hop authentication problem.
Use CredSSP
I suppose there are a variety of ways to overcome the double-hop problem. This being a testing scenario, CredSSP seems appropriate (beware the security risk). Here's the proof of concept.
First you have to enable CredSSP on both computers:
PS C:\> Enable-WSManCredSSP Client -DelegateComputer target.ad.example.com
PS C:\> Invoke-Command { Enable-WSManCredSSP Server} -ComputerName target.ad.example.com
Then you can remote to the target using CredSSP:
PS C:\> $credential = Get-Credential example\target-admin
PS C:\> Enter-PSSession target.ad.example.com -Credential $credential -Authentication CredSSP
[target.ad.example.com]: PS C:\>
And psexec -s works:
[target.ad.example.com]: PS C:\> psexec -s whoami
C:\PsTools\PsExec.exe :
+ CategoryInfo : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
Connecting to local system...Starting PSEXESVC service on local system...Connecting with PsExec service on
target...Starting whoami on target...
whoami exited on target with error code 0.
nt authority\system
https://github.com/mkellerman/Invoke-CommandAs
Made a function to Invoke-Command as SYSTEM, or provided credential, against local/remote computer. Returns PSObjects, handles network interruptions and resolves any Double-Hop issues.
Try it out let me know if this resolves your issues.

How to load Powershell ISE 3 with powershell v2 inside?

I just installed new powershell 3 on my Windows 7 machine and than I found out that new version of powershell doesn't work with Sharepoint 2010.
I also found a solution for this problem (here or here). But it only solves the problem for the standart powershell console. As we do most of the work through ISE, I wonder if it is possible to do the same thing in ISE?
I tried to add Version parameter, but ISE doesn't know it. I tried to type powershell -version 2 into ISE's console, but it didn't help.
If it would not be possible, I have another question: I need to use ISE with Sharepoint 2010, so how can I uninstall powershell 3 and new ISE?
This is a known issue when the Windows Management Framework 3.0 update is installed (it inlcudes PS 3.0) which, as it uses .net 4.0 makes all the SP2010 cmdlets (which are 3.5), incompatible.
The console application can accept the "-version 2" switch, but as pointed out this is not compatible with the ISE.
It is a known issue, another article suggests uninstalling the WMF update and re-booting the server, which I think is the only real answer to the last part of your question.
You can do this by creating new PSSession.
Register-PSSessionConfiguration -Name PS2 -PSVersion 2.0 –ShowSecurityDescriptorUI
# Please consult system admin when your run set-item and Enable-WSManCredSSP command
Set-Item wsman:localhost\client\trustedhosts -value * -Confirm:$false -Force
Enable-WSManCredSSP -Role Client –DelegateComputer * -Force
Enable-WSManCredSSP -Role Server -Force
# For test purpose
# Get-WSManCredSSP
# get-item wsman:localhost\client\trustedhosts
$cred = Get-Credential
$session = New-PSSession -ComputerName $env:COMPUTERNAME -authentication credssp -ConfigurationName PS2 -Credential $cred
Enter-PSSession $session
# 2.0 runtime
Add-PSSnapin microsoft.sharepoint.powershell
$web = Get-SPWeb http://SPSite/
$web.Url
Exit-PSSession
Unregister-PSSessionConfiguration -Name PS2
Disable-WSManCredSSP -Role Client
Disable-WSManCredSSP -Role Server
If you don't exit PSSession, you can run 2.0 runtime command from Powershell ISE 3.