Get remote registry value - powershell

I have the below script that I want it to go out to multiple servers and get the value of a registry. Unfortunately it is currently just posting back the local registry value of the machine that I am running the script on.
How do I get the script to run against remote registry?
SCRIPT:
clear
#$ErrorActionPreference = "silentlycontinue"
$Logfile = "C:\temp\NEWnetbackup_version.log"
Function LogWrite
{
param([string]$logstring)
Add-Content $Logfile -Value $logstring
}
$computer = Get-Content -Path c:\temp\netbackup_servers1.txt
foreach ($computer1 in $computer){
$Service = Get-WmiObject Win32_Service -Filter "Name = 'NetBackup Client Service'" -ComputerName $computer1
if (test-connection $computer1 -quiet)
{
$NetbackupVersion1 = $(Get-ItemProperty hklm:\SOFTWARE\Veritas\NetBackup\CurrentVersion).PackageVersion
if($Service.state -eq 'Running')
{
LogWrite "$computer1 STARTED $NetbackupVersion1"
}
else
{
LogWrite "$computer1 STOPPED $NetbackupVersion1"
}
}
else
{
LogWrite "$computer1 is down" -foregroundcolor RED
}
}

You can try using .net:
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer1)
$RegKey= $Reg.OpenSubKey("SOFTWARE\\Veritas\\NetBackup\\CurrentVersion")
$NetbackupVersion1 = $RegKey.GetValue("PackageVersion")

Try the Remote Registry Module, the registry provider cannot operate remotely:
Import-Module PSRemoteRegistry
Get-RegValue -ComputerName $Computer1 -Key SOFTWARE\Veritas\NetBackup\CurrentVersion -Value PackageVersion

If you have Powershell remoting and CredSSP setup then you can update your code to the following:
$Session = New-PSSession -ComputerName $Computer1 -Authentication CredSSP
$NetbackupVersion1 = Invoke-Command -Session $Session -ScriptBlock { $(Get-ItemProperty hklm:\SOFTWARE\Veritas\NetBackup\CurrentVersion).PackageVersion}
Remove-PSSession $Session

another option ... needs remoting ...
(invoke-command -ComputerName mymachine -ScriptBlock {Get-ItemProperty HKLM:\SOFTWARE\VanDyke\VShell\License -Name Version }).version

For remote registry you have to use .NET with powershell 2.0
$w32reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$computer1)
$keypath = 'SOFTWARE\Veritas\NetBackup\CurrentVersion'
$netbackup = $w32reg.OpenSubKey($keypath)
$NetbackupVersion1 = $netbackup.GetValue('PackageVersion')

If you need user's SID and browse remote HKEY_USERS folder, you can follow this script :
<# Replace following domain.name with yours and userAccountName with remote username #>
$userLogin = New-Object System.Security.Principal.NTAccount(“domain.name“,”userAccountName“)
$userSID = $userLogin.Translate([System.Security.Principal.SecurityIdentifier])
<# We will open HKEY_USERS and with accurate user’s SID from remoteComputer #>
$remoteRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘Users’,”remoteComputer“)
<# We will then retrieve LocalName value from Control Panel / International subkeys #>
$key = $userSID.value+”\Control Panel\International”
$openKey = $remoteRegistry.OpenSubKey($key)
<# We can now retrieve any values #>
$localName = $openKey.GetValue(‘LocaleName’)
Source : http://techsultan.com/how-to-browse-remote-registry-in-powershell/

Related

How do I remote into multiple remote computers via PS to discover one specific app and determine the version number on each remote device? No output

FYI: I'm very new to PS and I'm using this as a learning opportunity. Again, I'm trying to find a
specific application on a list of multiple remote devices and determine the version number of the
application on their corresponding host system. I attempted this via a registry query (found this to
be challenging) and then I used Get-WMIObject. As of now, I'm working with this as my script. It's
not producing any output; instead, it returns to the command prompt with no errors or messages.
Script to find specific application and version in multiple remote devices:
$Servers = Get-Content -Path C:\\files\Serverlist.txt
$CIMSession = New-CIMSession -ComputerName $Servers Get-Credentials
$Vendor = "App Name"
foreach($Serv in $Servers) {
If(Test-Connection -ComputerName $Serv -Count 1 -Quiet) {
$Status = Get-Ciminstance Win32_Product -Computername $Serv | Where-object {$_.Version -contains
$Vendor}
if($Status) {
Out-file -Filepath C:\\files\AppVerResults.txt
}
}
}
I also tried adjusting the following section of the script as shown below but it presented me with the error "Get-CimInstance : Access is denied." Is this error message due to group policy or so? I am able to remote into the device corresponding to the message via RDP.
if($Status) {
$Servers + " - "
$Status | Out-file -Filepath C:\\files\AppVerResults.txt
}
}
}
Should I go about it via invoke-command or registry query? I'm slowly picking things up so I'll continue my research but I was hoping to get some advice in the meantime.
I still believe searching the registry is the easier way to go unless you have the specific file path for the .exe.
Use this function to find software on a remote, or local PC. Theres a filter option by specifying -SoftwareName (to look for).
Find-Software -ComputerName Remote_ComputerName -SoftwareName 'SQL'
Also accepts pipeline input, as well as multiple computer names to query for.
Find-Software -ComputerName ComputerOne, ComputerTwo, ComputerThree -SoftwareName 'SQL'
'ComputerOne','ComputerTwo' | Find-Software -SoftwareName 'SQL'
Exporting is also allowed by piping to an Export-* cmdlet.
Heres the code:
Function Find-Software {
[cmdletBinding()]
Param(
[Parameter(Mandatory=$false,
ValueFromPipeLine=$true,
ValueFromPipeLineByPropertyName=$true)]
[Alias('cn','name')]
[string[]]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory=$false)]
[String]$SoftwareName
)
Begin{
#Get Computer Names to check software version for
$Server_List = Get-Content -Path "C:\files\Serverlist.txt"
#Get Credentials for Script Scope once.
$Credentials = Get-Credential
}
Process{
if($PSBoundParameters.ContainsKey('SoftwareName')){
foreach($Computer in $ComputerName){
Try{
$PSSession = New-PSSession -ComputerName $Computer -Credential $Credentials -EnableNetworkAccess -ErrorAction Stop
$Software_List = Invoke-Command -ScriptBlock {
Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" } -Session $PSSession
$Software_List = $Software_List | Where-Object -FilterScript {$_.DisplayName -match $SoftwareName} | Sort-Object -Property DisplayName
foreach($Software in $Software_List){
if($Software){
[PSCustomObject]#{
"Computer Name" = $Computer
"Software Name" = $Software.DisplayName
" Version " = $Software.DisplayVersion
}
} else {
[PSCustomObject]#{
"Computer Name" = $Computer
"Software Name" = "Not found"
" Version " = $null
}
}
}
} Catch {
"Unable to connect to PC: $Computer"
"Error: $($Error[0].Message.Split('.')[1].Trim())"
}
}
} else {
foreach($Computer in $ComputerName){
Try{
$PSSession = New-PSSession -ComputerName $Computer -Credential $Credentials -EnableNetworkAccess -ErrorAction Stop
$Software_List = Invoke-Command -ScriptBlock {
Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" } -Session $PSSession
$Software_List = $Software_List | Sort-Object -Property DisplayName
foreach($Software in $Software_List){
[PSCustomObject]#{
"Computer Name" = $Computer
"Software Name" = $Software.DisplayName
" Version " = $Software.DisplayVersion
}
}
} Catch {
"Unable to connect to PC: $Computer"
"Error: $($Error[0].Message.Split('.')[1].Trim())"
}
}
} #end ELSE statement
} #end PROCESS block
End {
if(Get-PSSession){
Get-PSSession | Remove-PSSession
}
} #end END block - Perform Session Clean Up
} #end FUNCTION
Simply modify it to fit your needs :)

Change value in registry on multiple servers using credentials

Looking to enable reg key on multiple remote machines.
Attempt 1:
$Servers = Get-Content "C:\PowerShell\TestServers.txt"
$Path = "HKLM:\SYSTEM\CurrentControlSet\Services\"
$Property = "*REG_WORD NAME*"
$Value = "1"
Foreach ($Server in $Servers)
{
Set-ItemProperty -Path $Path -Name $Property -Value $Value
}
Error: Set-ItemProperty : Requested registry access is not allowed.
NOTE: checked effective access, the account being used has FULLControl over the specific hive
Attempt 2:
Created a function, added the get-credential cmdlet
function Set-RemoteRegistryValue {
param (
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
$null = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
} -Credential $Credential
}
I am now able to call the function and set the reg key value as desired, but only one machine at a time:
$remoteKeyParams = #{
ComputerName ='name'
Path = "HKLM:\SYSTEM\CurrentControlSet\Services\"
Name = "*keyname*"
Value = "1"
}
Set-RemoteRegistryValue #remoteKeyParams -Credential (Get-Credential)
I have tried putting multiple machines in as a string, and a text file:
[string]$ComputerName = "name","name","name"
ComputerName = c:\temp\testservers.txt
Am I doing something very wrong here?
Confirm you have one server per line and then this is how you should write it.
$Servers = Get-Content "C:\PowerShell\TestServers.txt"
$Path = "HKLM:\SYSTEM\CurrentControlSet\Services\"
$Property = "*REG_WORD NAME*"
$Value = "1"
Invoke-Command -ComputerName $servers -ScriptBlock {
Set-ItemProperty -Path $using:Path -Name $using:Name -Value $using:Value
} -Credential $Credential
When you pass all the server names to Invoke-Command it will run them all asynchronously (up to 32 by default on 5.1)

Remove specific Local user accounts from remote servers

We have a large number of servers with multiple accounts installed on the local machine, I need to remove the multiple local accounts from multiple servers and check they have been removed.
The only way I can see of doing this is by using PS-remoting (in our environment, it's totally locked down, so this is the only option)
As I understand you many new commands such as Remove-localuseraccount are only supported on new versions of PS (we have a project to upgrade to the better version)
$Computers = Get-Content C:\script\servers.txt
ForEach ($Computer in $Computers) {
$Session = New-PSSession -ComputerName $Computer
Invoke-Command -Session $session -ScriptBlock {
}
But what command can I run to check the multiple accounts list I have and remove if it finds any?
Desired State Configuration: Your life made easy
This will disable the local accounts and keep them that way utilizing DSC.
Setup.ps1
Install-Module -Name 'PSDscResources'
Set-Location -Path "$env:LocalAppData\Temp"
Configuration 'DisableDefaults'
{
Import-DscResource -ModuleName 'PSDscResources'
Node 'localhost'
{
User 'Default'
{
Username = 'DefaultAccount'
Disabled = $True
}
User 'Guest'
{
Username = 'Guest'
Disabled = $True
}
User 'Admin'
{
Username = 'Administrator'
Disabled = $True
}
}
}
DisableDefaults
Execution.ps1
Set-Location -Path "$env:LocalAppData\Temp\DisableDefaults"
$Computers = Get-Content -Path 'C:\script\servers.txt'
$Sessions = New-CimSession -ComputerName $Computers
Start-DscConfiguration -Path '.' -CimSession $Sessions -Wait -Force -Verbose
Remove-CimSession -CimSession $Sessions
You can cut the CimSession[] and just pass -ComputerName $Computers. Also, you can utilize the -Credential $PSCred argument.

Check the AppPool status through power-shell and start that on remote machine

The requirement is to extract the server name one by one and check the AppPool status, if that is found to be stopped, make it running. below code is not helping out.
$ErrorActionPreference = "Continue"
$status = gc -path "D:\Servers\server.txt"|ForEach-Object (invoke-command -ComputerName $_ -ScriptBlock {Import-Module Webadministration Get-WebAppPoolState -name (gc "D:\AppPool.txt")})
if ($status.value -eq "Started")
{
Write-Host ("ApppPool already running")
}
else
{
Invoke-Command -ScriptBlock {Start-WebAppPool}
Write-host ("AppPool has started successfully")
}
There were multiple problems with your code, I've gone through them individually so you can see what was stopping it from working correctly.
The syntax for foreach was wrong, you needed to use {} not () in this case. Normal brackets are only used like this ForEach ($number in $numArray ) {CODE} which you aren't.
You were checking $status outside the foreach loop - so it so was evaluating $status only once (with the final computers AppPool status) rather than for each computer.
Your second Invoke-Command didn't have a ComputerName parameter specified so was only running the command locally not against the remote computer, meaning the AppPool would never be started.
As you were specifying the AppPool name using gc "D:\AppPool.txt" this file would have to be present on every remote computer for it to work. I've changed this to be passed into the command as an argument so the file only needs to be on the computer running the script.
$Credentials = Get-Credential
$AppPools = Get-Content "D:\AppPool.txt"
$Servers = Get-Content -Path "D:\Servers\server.txt"
ForEach ($Server in $Servers) {
ForEach ($AppPool in $AppPools) {
$AppPoolState = Invoke-Command -ComputerName $Server -ScriptBlock {Import-Module WebAdministration; Get-WebAppPoolState -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
if ($AppPoolState.Value -eq "Started")
{
Write-Host "$AppPool AppPool already running on $Server"
}
else
{
Invoke-Command -ComputerName $Server -ScriptBlock {Start-WebAppPool -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
Write-Host "$AppPool AppPool started on $Server"
}
}
}
Note: I run a non-privileged account so have to supply Credentials. If the account you're running the script as has appropriate permissions to all the remote computers you can remove the three Credentials references.

Remote Registry using Enter-PSSession

I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")