By now you may have PowerShell installed on more than a few machines. Maybe you even have the PowerShell CTP installed somewhere. Do you remember where you’ve installed PowerShell? Could someone else have installed PowerShell on a system without your knowledge? Perhaps an eager user?
I put together a PowerShell function you can use to check if PowerShell is installed on a remote system.
Function Get-PowerShellInstall {
Param ([string]$computer="localhost")
#registry hive constants
$HKLM=2147483650
$HKCU=2147483649
$HKCR=2147483648
$HKEY_USERS=2147483651
#there is no provision for alternate credentials
$Reg = [WMIClass]"\$computer\root\default:StdRegProv"
$basePath="software\microsoft\powershell\1"
$ShellPath="shellids\Microsoft.PowerShell"
$EnginePath="PowerShellEngine"
$InstallPath=$reg.GetStringValue($HKLM,(Join-Path $basePath $ShellPath),"path").svalue
#only get other values if able to get a value for $InstallPath
if ($InstallPath) {
$Installed=$True
$ExecutionPolicy=$reg.GetStringValue($HKLM,(Join-Path $basePath $ShellPath),"ExecutionPolicy").svalue
#if ExecutionPolicy key is missing then assume Restricted
if (-not $ExecutionPolicy) {
$ExecutionPolicy="Restricted"
}
$PowerShellVersion=$Reg.GetStringValue($HKLM,(Join-Path $basePath $EnginePath),"PowerShellVersion").svalue
$RunTimeVersion=$Reg.GetStringValue($HKLM,(Join-Path $basePath $EnginePath),"RunTimeVersion").svalue
}
else {
$InstallPath=""
$Installed=$False
$ExecutionPolicy=""
$PowerShellVersion=""
$RunTimeVersion=""
}
$obj=New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "Computer" -Value $computer.ToUpper()
$obj | Add-Member -MemberType NoteProperty -Name "Installed" -Value $Installed
$obj | Add-Member -MemberType NoteProperty -Name "InstallPath" -Value $InstallPath
$obj | Add-Member -MemberType NoteProperty -Name "ExecutionPolicy" -Value $ExecutionPolicy
$obj | Add-Member -MemberType NoteProperty -Name "Version" -Value $PowerShellVersion
$obj | Add-Member -MemberType NoteProperty -Name "RunTimeVersion" -Value $RunTimeVersion
write $obj
}
Don’t try to copy and paste the function from the blog entry as it screws up some formatting details. I’ve attached it as a text file.
The script uses WMI and the StdRegProv to remotely connect to a specified computer’s registry. To accomplish this we create an instance of a WMIClass object using the [WMIClass] type adapter.
$Reg = [WMIClass]"\$computer\root\default:StdRegProv"
One drawback is that there is no way to specify alternate credentials so you can only connect to remote systems with your current credentials.
Once connected we can read installation information from the registry. Instead of returning basic information, the function returns a custom object. When you run the function you should get a result like this:
Computer : LOCALHOST
Installed : True
InstallPath : C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
ExecutionPolicy : RemoteSigned
Version : 1.0
RunTimeVersion : v2.0.50727
But because the function returns an object and can accept input you can do things like this:
cat servers.txt | % { get-powerShellInstall $_ | where {$_.Installed}} | format-table Computer,InstallPath,ExecutionPolicy,Version -auto
Now you should be able to easily find out where PowerShell is installed and how it is configured.
Nice!
Now, given the information that PS is not installed, could you then remotely install PS on that system (using the current credentials)?
The problem is that the PowerShell installation is not an MSI. I don’t know if the EXE package supports an unattended install.
Jeff
Do you think PS v2.0 will be in MSI form?
The current CTP does ship as an MSI. Version 1 ships as a hot fix. It looks like you could use /quiet /passive switches. Run the exe for your system with -? to see all the switches.
Jeff
Since the long-term plan is to have PowerShell included with new versions of Windows (like 2008), an MSI shouldn’t be necessary at some point.