How to ensure that we are using powershell 2.0? - powershell

We are providing scripts to clients that will be working only in Powershell 2.0.
Through command we can ensure that powershell 2.0 is installed like below
$version = Get-host | Select-object Version
But if we provide script how to ensure that they are executing it from Powershell 2.0?
When executing the script , Powershell 2.0 features may give script errors while initiating the script itself.Isn't it?

You can annotate your script with #requires and state that it shouldn't run on anything less than PowerShell v2:
#requires -Version 2.0
(Side note: This is surprisingly hard to find even if you know vaguely that it exists.)

Relying on the host version is not the safest thing to do as the script can be run on hosts that do not have the same host version as PowerShell's version.
The $PSVersionTable variable was added in v2. You can check if the variable exists, if it does you're running v2 and above, you can also check PSVersion.Major property:
if($PSVersionTable)
{
'PowerShell {0}' -f $PSVersionTable.PSVersion.Major
}
else
{
'PowerShell 1'
}

I'd do something like this:
# get version
$ver = $PsVersionTable.psversion.major
# Check to see if it's V2
If ($ver -NE 2)
{"incorrect version - exiting; return}
# Everything that follows is V2
Hope this helps!

Try to use $PSVersionTable
You will get something like:
Name Value
---- -----
CLRVersion 2.0.50727.5456
BuildVersion 6.1.7601.17514
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.1

Related

Type not found in PowerShell session: "Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage"

Below is example variable which once entered into PowerShell Core reports that the type was not found:
[Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage] $test = $null
InvalidOperation: Unable to find type
[Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage].
However once you run the following code:
Get-AppxPackage -PackageTypeFilter Main
Then the previous variable declaration will be just fine (no error):
[Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage] $test = $null
How do I make this type get recognized by PowerShell session without running Get-AppxPackage?
I tried with using namespace Microsoft.Windows and few other namespaces but it doesn't work.
Environment data:
$PSVersionTable
Name Value
---- -----
PSVersion 7.0.3
PSEdition Core
GitCommitId 7.0.3
OS Microsoft Windows 10.0.19041
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
I figured out, at the top of your script add this line:
Add-Type -AssemblyName Microsoft.Windows.Appx.PackageManager.Commands
Now we can use all the types from that assembly:
[Microsoft.Windows.Appx.PackageManager.Commands.AppxPackage] $test = $null
No error.
Reference

Can't Get Screen Resolutions from Remote Computers via PowerShell Remoting

I'm trying to get correct screen resolutions from remote computers using Invoke-Command and a PSSession but both methods report one resolution of 1024 x 768. There are two screens, 1920 x 1080 and 1280 x 720. This is not a DPI thing.
Executing the code below (remotely) outputs the below snippet. Executing interactively, the correct resolutions are reported. All the other working methods posted online have the same behavoir.
Output:
PS > Add-Type -AssemblyName System.Windows.Forms
PS > [System.Windows.Forms.Screen]::AllScreens
BitsPerPixel : 0
Bounds : {X=0,Y=0,Width=1024,Height=768}
DeviceName : WinDisc
Primary : True
WorkingArea : {X=0,Y=0,Width=1024,Height=768}
It's surprising nothing in CIM can get these details from MULTIPLE monitors remotely, that I have found. Maybe time for a feature request to beef up some CIM cmdlets in 7.
I guess a workaround could be creating a Scheduled task on all target computers that runs a script locally to output the info to a local file, then use remoting to get the file or data.
If anyone has overcome this, your feedback would be greatly appreciated amongst the rest of us with this roadblock.
PowerShell 7:
Name Value
---- -----
PSVersion 7.0.1
PSEdition Core
GitCommitId 7.0.1
OS Microsoft Windows 10.0.18363
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Windows PowerShell:
Name Value
---- -----
PSVersion 5.1.18362.752
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.18362.752
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Windows 10 Pro
I am not sure if this issue was resolved or not, but I am not able to find any way to get resolution of remote PC via powershell (i.e. using non-interactive session). Hence came up with the logic to get this via registry values :
Note :-
This script is tested with Windows 10 only
This will require remote user to have read access to registry value in variable "$videoRegistryPath"
$videoRegistryPath = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Configuration\'
$all_monitor_array_X=#()
$all_monitor_array_Y=#()
$screen_cnt= (Get-CimInstance -Namespace root\wmi -ClassName wmimonitorid -ErrorAction SilentlyContinue | measure )
$NumberOfScreens= $screen_cnt.Count
$allVideoGraphics = Get-ChildItem -Path ($videoRegistryPath).Replace('HKEY_LOCAL_MACHINE','HKLM:')
foreach ($instance in $allVideoGraphics ) {
$allVideoGraphicsChild= Get-ChildItem -Path ($instance.Name).Replace('HKEY_LOCAL_MACHINE','HKLM:')
if ($allVideoGraphicsChild.Property.Contains('PrimSurfSize.cx')) {
$allVideoGraphicsChildProperty = Get-ItemProperty -Path ($allVideoGraphicsChild.Name).Replace('HKEY_LOCAL_MACHINE','HKLM:')
$Screen_X= $allVideoGraphicsChildProperty.'PrimSurfSize.cx'
$Screen_Y=$allVideoGraphicsChildProperty.'PrimSurfSize.cy'
$all_monitor_array_X += $Screen_X
$all_monitor_array_Y += $Screen_Y
}
}
for ($i=0;$i -le ($NumberOfScreens-1);$i++){
[PSCustomObject]#{
Values = $all_monitor_array_X[$i];
Instance = "Monitor_"+($i)+"_x_coordinate";
}
[PSCustomObject]#{
Values = $all_monitor_array_Y[$i];
Instance = "Monitor_"+($i)+"_y_coordinate";
}
}
Hope this will help in this specific requirement to get resolution of remote computer using non-interactive session.

Forcing version 2 on remote session for SharePoint management using Powershell

It seems that SharePoint 2010 is still incompatible with PowerShell version 3.0.
I am already aware that it is possible to force compatibility by executing PowerShell with the -v 2 switch, but is there a way to force this compatibility mode when using a remote session via PSSession as using a remote desktop is quite impractical just to launch a shell?
If you start the client PowerShell with -v 2. Then outgoing remote sessions should use v2 on the remote end automatically.
Update: it appears I am mistaken - I think in fact I had discussed this with the PowerShell team, but apparently it's not fixed. Anyway, you can create a session configuration on the server that is forced to version 2.0:
PS> $psversiontable
Name Value
---- -----
PSVersion 3.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.18010
BuildVersion 6.2.9200.16434
PSCompatibleVersions {1.0, 2.0, 3.0}
PSRemotingProtocolVersion 2.2
PS> Register-PSSessionConfiguration -PSVersion '2.0' -Name "powershell2"
Accept all of the prompts. Now, you must pass the name of the new remote session configuration when invoking from the client side (in this example, the client and server are the same machine: my desktop)
PS> icm localhost -ConfigurationName powershell2 { $psversiontable }
Name Value
---- -----
PSRemotingProtocolVersion 2.1
BuildVersion 6.1.7600.16385
PSCompatibleVersions {1.0, 2.0}
PSVersion 2.0
CLRVersion 2.0.50727.6400
WSManStackVersion 2.0
SerializationVersion 1.1.0.1
As you can see, the remote endpoint is running 2.0.
I hope this helps.

Powershell v3.0 pipe issue

I'm having trouble with this command:
gc .\domains.txt | Get-ADDomain
As the name implies, domains.txt contains a list of Active Directory to query (all domains are in the same forest).
If I run it on my Windows 8 machine everything works fine and I get the expected results, instead on a Windows 2008 R2 SP1 member server (not a DC) with WMF 3.0 I get result only from the first domain in the list and for the others:
Get-ADDomain : A referral was returned from the server
If I query a domain in the list with:
Get-ADDomain <Domain name here>
it works fine.
My Workstation
Microsoft Windows 8 Enterprise (6.2.9200) x64
PS D:\Tools\Powershell> $PSVersionTable
Name Value
---- -----
PSVersion 3.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.18010
BuildVersion 6.2.9200.16384
PSCompatibleVersions {1.0, 2.0, 3.0}
PSRemotingProtocolVersion 2.2
Server
Microsoft Windows Server 2008 R2 Standard SP1 (6.1.7601) x64
PS C:\Tools\Powershell> $PSVersionTable
Name Value
---- -----
WSManStackVersion 3.0
PSCompatibleVersions {1.0, 2.0, 3.0}
SerializationVersion 1.1.0.1
BuildVersion 6.2.9200.16398
PSVersion 3.0
CLRVersion 4.0.30319.269
PSRemotingProtocolVersion 2.2
Update
If i run on the server:
gc .\domains.txt | %{ Get-ADDomain $_ }
it runs fine
TRACE
trace-command -Name ParameterBinding { "DOMAIN_1","DOMAIN_2" | Get-ADDomain } -PSHost
Server: http://pastebin.com/sRVJHaCU
Workstation: http://pastebin.com/kj3JV6nV
Thanks in advance
I found an article that may help.
http://technet.microsoft.com/en-us/library/ee617224.aspx
From the look of your script you are providing the server using the text file. Is it possible the problem is the Windows 2008 server you are running the PowerShell script on is not in the same domain or the user you are logged in as does not have access to the domains where the other servers are members?
snippet from the above article:
-If the Server parameter is specified and the Credential parameter is not specified:
--The domain is set to the domain of the specified server and the cmdlet checks to make sure that the server is in the domain of the
LocalComputer or LoggedOnUser. Then the credentials of the current
logged on user are used to get the domain. An error is returned when
the server is not in the domain of the LocalComputer or LoggedOnUser.
You might try adding the additional parameters for the Get-ADDomain commandlet such as -Identity, -AuthType, and -Credential
Get-ADDomain [-Identity] [-AuthType { |
}] [-Credential ] [-Server ]
[]
Powershell v3.0 pipe issue
I just tried to run the cmdlet 'gc .\text.txt | Get-ADDomain' from a virtual Server 2008 R2 box that I have. I built a text file in the following format:
Domain1
Domain2
Domain3
One thing to be sure of is that each domain is on it's own line in the text file. I can understand why the one syntax worked when you piped the STDOUT to:
%{ Get-ADDomain $_}
because you are looping through all the information contained in the text file and only have the cmdlet work on a single value at a time. Unfortunately I don't have the RSAT package on my Win 8 desktop, so I can't test from my desktop. Hopefully this helps a little bit.

PowerShell's Invoke-Expression missing param

I thought that I had the latest CTP of PowerShell 2 but when I try the command:
invoke-expression –computername Server01 –command 'get-process PowerShell'
I get an error message:
A parameter cannot be found that matches parameter name 'computername'.
So the question is: How can I tell which version of PowerShell I have installed? And what the latest version is?
From last night's build (which means you might have this in CTP3 but if not, you'll get it in the next public drop):
[4120:0]PS> $psversiontable
Name Value
---- -----
CLRVersion 2.0.50727.3521
BuildVersion 6.1.7047.0
PSVersion 2.0
WSManStackVersion 2.0
PSCompatibleVersions {1.0, 2.0}
SerializationVersion 1.1.0.1
PSRemotingProtocolVersion 2.0
Experiment! Enjoy! Engage!
Jeffrey Snover [MSFT]
Windows Management Partner Architect
The problem is that from CTP 1 to CTP2, they switched up the Invoke stuff, all the remoting stuff is done through Invoke-Command now, and Invoke-Expression is solely for turning a string into a script ;)
P.S.: If you're on v2 you can run $PSVersionTable to see a list of versions including the CLR and Build versions.
$host.version.tostring() will return the version number.
RTM of v1 is 1.0.0.0
Couldn't honestly tell you what the latest version of the previews are because I haven't had a chance to play yet.
The latest CTP is CTP2 released on 05/02/08 and can be found here. Remoting requires WinRM to be installed on both the calling machine and the target machine. Included in the CTP is a script to configure WS-Management called Configure-WSMan.ps1.
This command should get you the version number of PowerShell that you have installed.
Get-Command "$PSHome\powershell.exe" | Format-List FileVersionInfo
V1.0 is 6.0.5430.0
CTP2 is 6.1.6585.1
I don't have the version number for the first CTP on hand, but I can find it if you really need it.
I'm guessing that this is a change to the cmdlet made during the configuration process Configure-Wsman.ps1. I don't have an environment setup to test right now, but I'm guessing something went wrong with the configuration. I can verify that on XP the parameter is not available (duh). I'd assume that you will find the same on Vista/08 without the configuration completed.
If the $PSVersionTable variable doesn't exist, then you are running V1.
If it exists, then the version will be available as $PSVersionTable.PSVersion.
function Get-PSVersion {
if (test-path variable:psversiontable)
{$psversiontable.psversion}
else
{[version]"1.0.0.0"}
}