Remote Registry using Enter-PSSession - powershell

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")

Related

Problem with test-path on computer from another domain

Im trying to test a remote folder in a computer from another domain with -credential
This command works fine:
Invoke-Command -ComputerName "server" -credential domain\user -ScriptBlock {Test-Path -Path "\\server\s$\temp"}
But if i use it in a script fails:
$servers = Get-Content "servers.txt"
$Path = "\\D$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (invoke-command -computername $server -credential $cred -ScriptBlock {Test-Path -Path "\\$server\$Path"})
}
PD: All this option works in a server of my domain without specify another credentials.
Besides the syntax issue with missing the script block after your if statement, this should work as long as you specify the variables as remote ones. Use $using or pass it as an argument with -ArgumentList.
$servers = Get-Content "servers.txt"
$Path = "\\c$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (
invoke-command -computername $server -ScriptBlock {
Test-Path -Path "\\$using:server\$using:Path"
}
) { <#do code here#> }
}
If you run the shell with the proper credentials to begin with, all youd have to do is use Test-Path directly but I understand that you'd like to try using the -Credential parameter.

PowerShell cannot use New-PSSessions right after Invoke-CimMethod (The runspace state is not valid for this operation)

The two code below works independently, however, they cannot work in the same script. I really need help, there's got to be something incompatible.
The first part of my script uses Invoke-CimMethod to Enable-PSRemoting, and it works.
Variables
$hostname = 'PC1'
$Session = New-PSSession $hostname
$DestinationPath = "C:\windows\temp"
Part 1
$SessionArgs = #{
ComputerName = $hostname
Credential = $credential
SessionOption = New-CimSessionOption -Protocol Dcom
}
$MethodArgs = #{
ClassName = 'Win32_Process'
MethodName = 'Create'
CimSession = New-CimSession #SessionArgs
Arguments = #{
CommandLine = "powershell Start-Process powershell -ArgumentList 'Enable-PSRemoting -Force'"
}
}
Invoke-CimMethod #MethodArgs
The second part of my code works if the first part above is not present. It is to create a TEMP folder, and then copy an entire folder into TEMP.
Part 2
Invoke-Command -Session $Session -ScriptBlock { Param($Destination) New-Item -Path $Destination -ItemType Directory -ErrorAction SilentlyContinue} -ArgumentList $DestinationPath
Copy-Item -Path "\\shared\folder\foo\bar" -ToSession $Session -Destination "C:\windows\temp\" -recurse -force
Error
Copy-Item : The runspace state is not valid for this operation.
What's weird is I've inserted the Invoke-CimMethod to many other scripts that does similar things and it works fine, like for example
Example of it working
$env:hostname
$env:process
$SessionArgs = #{
ComputerName = $env:hostname
Credential = $credential
SessionOption = New-CimSessionOption -Protocol Dcom
}
$MethodArgs = #{
ClassName = 'Win32_Process'
MethodName = 'Create'
CimSession = New-CimSession #SessionArgs
Arguments = #{
CommandLine = "powershell Start-Process powershell -ArgumentList 'Enable-PSRemoting -Force'"
}
}
Invoke-CimMethod #MethodArgs
$session = New-PSSession $env:hostname
ipconfig
Invoke-Command -Session $session -ScriptBlock {param($process) Stop-Process -ProcessName $process -Force} -ArgumentList $env:process
$Session | Remove-PSSession
Please help! I've tried everything, I even tried Get-CimSession | Remove-CimSession but that didn't work. Why is it incompatible?
I was able to fix this issue by putting the variable
$Session = New-PSSession $hostname
Right before Invoke-Command because I think when I sent enable-pssession it resets the connection.

Powershell invoke-command $input

I have a trouble.. Can someone help me?
Here is my Code :
$A = '123'
$servers = 'computer1'
$Properties = [ordered]#{A = $A
servers = $servers
}
$MyObject = New-Object -TypeName PSObject -Property $Properties
$MyObjec
...
$result = Invoke-Command -ComputerName Machine -UseSSL -InDisconnectedSession -ScriptBlock {
$MyObject.A
$MyObject.servers
$env:computername
}`
–InputObject $MyObjec -port 5986 -ConfigurationName myEndpoint -SessionOption #{OutputBufferingMode="Drop"} -Credential $credential | Receive-PSSession
$result
Question:
Why the $result doesn't show anything about $MyObject?
It only show $MyObjec (not in the invoke-command) and $env:computername (in the invoke-command)
How can I fix it?
P.S this is really what I want to make,
I want to get into multiple machine which in 6 different AD in the same time, but they should use different username,
and I need $A in the remote machine to deal another thing.
$A = '123'
$servers = 'computer1'
$Properties = [ordered]#{A = $A
servers = $servers
}
$MyObject = New-Object -TypeName PSObject -Property $Properties
$MyObjec
...
#Add
$servers#{'Machine1','Machine2','Machine3'}
Foreach ($servers in $servers) {
Star-Job {
$username = $servers+'account'
$password = $password
$credential = ....($username,$password)
$result = Invoke-Command -ComputerName $servers -UseSSL -InDisconnectedSession -ScriptBlock {
$MyObject.A
$MyObject.servers
$env:computername
}`
–InputObject $MyObjec -port 5986 -ConfigurationName myEndpoint -SessionOption #{OutputBufferingMode="Drop"} -Credential $credential | Receive-PSSession
$result
}
}
I will try -Argument-List and param{}
Beacase I try Start-Job with -Argument-List and $Using, there have an error.
Thank u for your reply!
Because the part within -Scriptblock { ... } gets executed on the remote system and has therefore no access to the variables on the local system (different scope).
You can change that by passing the variables to the remote system using the -Argument-List parameter like this:
Invoke-Command -ComputerName Machine -ArgumentList $MyObject -ScriptBlock {
param($MyObject)
$MyObject.A
}
Or use $using: to get access to the locally defined variables like that:
Invoke-Command -ComputerName Machine -ScriptBlock {
$using:MyObject.A
}

Problems using local variables in a remote commands

I need to write a script that takes in variables and makes a share on a remote system.
This works:
Invoke-Command -ComputerName server -ScriptBlock {$a = [WMICLASS]"Win32_Share"; $a.Create("C:\test","test",0)}
But this doesn't:
$sharepath = "C:\test"
$sharename = "test"
Invoke-Command -ComputerName server -ScriptBlock {$a = [WMICLASS]"Win32_Share"; $a.Create($sharepath,$sharename,0)}
I need a way to pass those values somehow.
The remote session can't read your local variables, so you need to send them with your command. There's a few options here. In PowerShell 2.0 you could:
1.Pass them along with -ArgumentList and use $arg[i]
$sharepath = "C:\test"
$sharename = "test"
Invoke-Command -ComputerName server -ScriptBlock {$a = [WMICLASS]"Win32_Share"; $a.Create($args[0],$args[1],0)} -ArgumentList $sharepath, $sharename
2.Pass them along with -ArgumentList and use param() in your scriptblock to define the arguments
$sharepath = "C:\test"
$sharename = "test"
Invoke-Command -ComputerName server -ScriptBlock { param($sharepath, $sharename) $a = [WMICLASS]"Win32_Share"; $a.Create($sharepath,$sharename,0)} -ArgumentList $sharepath, $sharename
In PowerShell 3.0, the using-variable scope was introduced to make it easier:
$sharepath = "C:\test"
$sharename = "test"
Invoke-Command -ComputerName server -ScriptBlock { $a = [WMICLASS]"Win32_Share"; $a.Create($using:sharepath,$using:sharename,0)}
You could read more about this on about_Remote_Variables # TechNet

Get remote registry value

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/