Powershell Microsoft.win32.registrykey Openremotebasekey Credentials
The nice thing about this command is you can also specify alternate credentials. However, it does require that WsMan is correctly configured for powershell remoting to work. Which, 9 times out of 10 in most environments it is not. Option 2 – The Microsoft.Win32.RegistryKey Class. Since Powershell allow to quite easily query API Endpoints, you can quickly benefit from a GUI to search for some keyword (against a user, a computer, whatever else) Each search result will have probably many properties (ie, hostname, IP address, serial number, etc) that will usable for defining your menu commands to call your favorite script. I am using the Microsoft.Win32.RegistryKey base class for connecting to the remote registry. When the connection initializes, we need to provide two variables: the computer name and the base key (for example, LocalMachine or LocalUser). Openremotebasekey Credentials I'm trying to write an application that will get some registry values from a remote computer. The user can provide a hostname or IP in a string and should be getting a registry value displayed on their screen.
I was reading the news groups (as I do all the time) and I have notice numerous request/questions regarding remote registry access in powershell. I thought I would try to see if I could shed some light on the subject. So without further delay... on with the show!Overview:
----------
Registry access in Posh is realatively simple and extremely powerful.
From a local stand point its as simple as:
PS> Set-Location HKLM:System
From a remote standpoint... you have to utilize the powers of .NET.
$ServerKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, ServerName)
C# Registrykey
For the purpose of this post... I am going to focus on the remote aspect. Local is cover in tons of documentation. So, cause of time, I am only going to address the .NET method.
I will start by giving you the Remote Registry Object useful Properties/Methods
Object
-------
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,MachineName)
Properties
-------------
Name
SubKeyCount
ValueCount
Methods (Not all.. just the ones I use often)
---------------------------------------------------
CreateSubKey
DeleteSubKey
DeleteSubKeyTree
DeleteValue
GetAccessControl
GetLifetimeService
GetSubKeyNames
GetType
GetValue
GetValueKind
GetValueNames
OpenSubKey
SetAccessControl
SetValue
As you can see... You can do basically everything you could ever want.
Now that you have a basic idea of what the .NET provider can give you... let put it to practical use.
Examples:
----------
Purpose: Get a list of Subkeys and Values of Specific Registry Key.
Result (only showing first 10 of each:)
Sub Keys
--------
App Management
App Paths
Applets
BITS
Control Panel
Controls Folder
CSCSettings
DateTimeDynamic
Openremotebasekey Powershell
DirectoryExplorer
Values
------
DevicePath
MediaPath
Unexpanded
SM_GamesName
SM_Configure
ProgramsName
ProgramFilesDir
CommonFilesDir
ProductId
WallPaperDir
MediaPath
ProgramFilesPath
-------------------------------------------
Purpose: Get the Value of each of the Values.
Result (only showing first 10:)
Values
------
DevicePath = [C:WINDOWSinf;C:DriversBroadcomWin2003]
MediaPathUnexpanded = [C:WINDOWSMedia]
SM_GamesName = [Games]
SM_ConfigureProgramsName = [Set Program Access and Defaults]
ProgramFilesDir = [C:Program Files]
CommonFilesDir = [C:Program FilesCommon Files]
ProductId = [69713-640-4031427-45876]
WallPaperDir = [C:WINDOWSWebWallpaper]
Powershell Opensubkey
MediaPath = [C:WINDOWSMedia]
ProgramFilesPath = [C:Program Files]
------------------------------------------------
Summary:
-----------
As you now can see. POSH is really powerful given its .NET access to the registry. Honestly... there is virtually nothing you can't do and its easy to boot. You have complete access to Registry keys/subkeys/values. You can even Create, Delete, and evaluate Values and keys. In the future I will be sharing a function I wrote to compare Registry Subkeys between machines. That has proven to be super valuable.
Well... That about does it (at least for today :) ) I think this is a pretty good start to your POSH .NET registry adventure. I will be expanding this as I have time.
As always... PLEASE PROVIDE FEEDBACK!!! :)
functionGet-RdpSessions { |
[CmdletBinding()] |
param ( |
[Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] |
$ComputerName |
, |
[Parameter()] |
[switch]$Force |
<# not yet implememnted |
, |
[Parameter()] |
[System.Management.Automation.Credential()] |
[System.Management.Automation.PSCredential]$Credential = [System.Management.Automation.PSCredential]::Empty |
#> |
) |
process { |
#force logic |
[bool]$forced=$false |
[string]$previousValue=''#hold as string in case this property's held as something other than int; i.e. we don't want to cause side effects |
if ($Force.IsPresent) { |
try { |
$previousValue= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$ComputerName).OpenSubKey('SYSTEMCurrentControlSetControlTerminal Server').GetValue('AllowRemoteRPC') |
write-verbose'$ComputerName's AllowRDP = $previousValue' |
if($previousValue-ne'1') { |
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$ComputerName).OpenSubKey('SYSTEMCurrentControlSetControlTerminal Server',$true).SetValue('AllowRemoteRPC',1) |
$forced=$true |
write-verbose'$ComputerName's AllowRDP Forced to 1' |
} |
} catch { |
write-verbose'$ComputerName's AllowRDP failed to use the force :(' |
#even if we fail here, we still proceed; as we may be able to see sessions on the remote machine even if we can't read from its registry |
} |
} |
#query session logic |
try { |
#https://ss64.com/nt/query-session.html |
#pull the results into a variable |
[string[]]$querySessionResult= (qwinsta '/server:$ComputerName') |
#it would be nice to figute out the fixed-width column sizes automatically, in case they vary; but as the ID column is right aligned, that's not so easy: |
#[string]$regex = '^' + (($querySessionResult[0] -split 'sb' | select -skip 1 | %{'(?<$($_.trim())>.{$($_.Length+1)}'}) -join ')') + '.*)$' |
#so instead using a fixed defintion: |
[string]$regex='^(?<SESSIONNAME>.{18})(?<USERNAME>.{18})(?<ID>.{11})(?<STATE>.{8})(?<TYPE>.{7})(?<DEVICE>.*)$'#column sizes from https://superuser.com/a/1000089/156700 |
$querySessionResult| select -skip 1|?{$_-match$regex} |%{ |
$matches.remove(0) |
$properties=@{} |
$Matches.Keys|%{$properties[$_] ='$($Matches[$_])'.Trim()} |
(New-Object-TypeName PSObject -Property $properties) |
} |
} finally { #regardless of whether the above works, ensure that if we forced things, we put them back how they were |
if($forced) { |
[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$ComputerName).OpenSubKey('SYSTEMCurrentControlSetControlTerminal Server',$true).SetValue('AllowRemoteRPC',$previousValue) |
write-verbose'$ComputerName's AllowRDP reset to $previousValue' |
} |
} |
} |
} |
#demo for one computer |
Get-RdpSessions-ComputerName $MyComputer-Force -Verbose |
#demo for all servers in AD: |
#uses Test-ConnectionQuickly workflow from here to avoid running against offline machines https://codereview.stackexchange.com/questions/97726/powershell-to-quickly-ping-a-number-of-machines |
$servers=Get-AdComputer {(OperatingSystem -like'*server*') -and (Enabled -eq$true)} |
$servers=Test-ConnectionQuickly$servers|? Online |
$servers|Get-RdpSessions-Force -Verbose |? Username |