Trying to Retrieve A Reg Value From Remote Machines Using Powershell - powershell

I am trying to retrieve a registry value from each computer using a for each loop and then output that value to a folder in a csv.
That part works fine. The part I am having an issue with is having powershell connect to the remote computers.
This is running internal only
I have admin rights across all workstations
Firewalls are configured to allow all traffic to pass
When I run this script I get this error for every workstation it tried to connect to:
Enter-PSSession : Connecting to remote server workstationX failed with
the following error message : WinRM cannot complete the operation.
Verify that the specified computer name is valid, that the computer
is accessible over the network, and that a firewall exception for the
WinRM service is enabled and allows access from this computer. By
default, the WinRM firewall exception for public profiles limits
access to remote computers within the same local subnet. For more
information, see the about_Remote_Troubleshooting Help topic. At
C:\Users\Rich_Ellis\Desktop\O365\O365Channels\O365Channel.ps1:5 char:2
+ {Enter-PSSession -ComputerName $Computer
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (workstationX:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed
My script is:
$Computers = Get-Content "C:\Users\Rich_Ellis\Desktop\O365\O365Channels\computers.txt"
foreach ($Computer in $Computers)
{Enter-PSSession -ComputerName $Computer
$key = 'HKLM:\SOFTWARE\Microsoft\Office\CLickToRun\Configuration'
(Get-ItemProperty -Path $key -Name CDNBaseUrl).CDNBaseUrl | Export-CSV -path "\\s00itstorage\OfficeChannel\$($env:COMPUTERNAME)-O365Channel03292018.csv"}
Any help would be appreciated. TIA

Molding a previous answer to your use-case:
$HKEY_LOCAL_MACHINE = 2147483650
$GwmiArgs = #{
Class = 'StdRegProv'
Namespace = 'Root\Default'
List = $True
}
ForEach ($Computer in #(Get-Content -Path 'C:\Users\Rich_Ellis\Desktop\O365\O365Channels\computers.txt'))
{
$GwmiArgs['ComputerName'] = $Computer
$Registry = Get-WmiObject #GwmiArgs
$Registry.GetStringValue(
$HKEY_LOCAL_MACHINE,
'SOFTWARE\Microsoft\Office\ClickToRun\Configuration',
'CDNBaseUrl'
).sValue | Export-CSV -Path "\\s00itstorage\OfficeChannel\$Computer-O365Channel03292018.csv"
}
This uses wmi instead of psremoting to poll the information which may be easier to rely on as it is already configured/enabled on most PCs and can utilize IP addresses due to DCOM/RPC (psremoting only supports kerberos by default)
This solution can be further improved by using Invoke-WmiMethod instead of creating a wmi object for each poll, but I haven't done the work already for that!

Related

How to Check User's Rights via powershell on a remote or local machine

I have a script that needs to check the user' rights on the remote machine in order to confirm the user has the permissions to copy their files. When this part of the script runs, it fails 90% of the time unless the user is already an admin on the remote machine.
This is my code:
write-host Checking User Rights
#if the user provides and IP address, find the hostname
if ($sourceComputerName -match $ipPattern) {
Get-Hostname
}
else {
$global:fullHostName = $env:COMPUTERNAME
}
Write-host $sourceFolder
$permissionQuery = (Get-Acl $sourcefolder.substring(1, $sourceFolder.length - 2)).Access | Where-Object { $_.IdentityReference -match $adminusername } | Select-Object IdentityReference, FileSystemRights
if (!$permissionQuery) {
Invoke-Command -FilePath "$PSScriptRoot\LocalAdmin.ps1" -ComputerName $fullHostName -ArgumentList "$sourceRemotePath"
}
else {
write-host "Admin Rights Already Exist for $adminusername at $sourceRemotePath"
}
clear-host
Here is the Get-Hostname Function:
function global:Get-Hostname {
$queryHostname = [System.Net.DNS]::GetHostEntry($sourceComputerName) | Select-Object HostName | format-table -HideTableHeaders
$stringHostName = Out-String -InputObject $queryHostname
$splitHostName = $stringHostName.split(".", 2)
$global:fullHostName = $splitHostName[0] -replace '\s', ''
[void]$fullHostName
}
Here is the error:
[DESKTOPXXXX] Connecting to remote server DESKTOPXXXX failed with the following error message : Access is denied. For
more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (DESKTOPXXXX:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken
Note: I am one of the network admins and I have full admin rights on the machine I ran this script on
For effective permissions, try out Get-NTFSEffectiveAccess from the NTFSSecurity module.
The way you're currently checking permissions doesn't check for any groups that $adminusername is a member of, and may not give you accurate information.
The most common reason for "Access is denied" is that your current user is not an administrator on the remote machine, though there are other reasons listed in the Troubleshooting Guide:
Powershell remoting is not (or only partially) enabled on the remote machine.
WinRM service is not running
Remote firewall profile is in "Public network" mode (only accepts powershell remoting from the same subnet)
The current running credentials are invalid for some reason e.g. password expired.
You are double-hopping (remote from PC1 to PC2, then remote again to PC3)
First, try manually providing credentials:
$cred = Get-Credential -UserName Domain\AdminUser -Message Remote
Invoke-Command -Computername $sourceComputerName -Credential $cred -ScriptBlock {Hostname}
If you still get errors, try re-running the remote powershell setup on the remote machine (and restart it):
Enable-PSRemoting -Force

Powershell forum with button calling script

I have a powershell forum for level 1.
Now it has been asked to add a button that calls an script for solving automatic outlook issues.
The script works when i call it direct on the computer itself (via .\outlook.ps1)
When i add it to the button it does not work.
The button itself works and is visible.
example code:
$button_Outlookrest_Click={
Get-ComputerTXTBOX
Add-logs -text "$ComputerName - Create new Outlook profile"
function button{
Copy-Item -Path "D:\path\Repair_outlook_Profile.ps1" -Destination "\\$ComputerName\C$\local" -Recurse
Invoke-Command -ComputerName $ComputerName -ScriptBlock {C:\local\Repair_outlook_Profile.ps1}
}
}
I have tested the code individual, and the following is working:
Copy-Item -Path "D:\path\Repair_outlook_Profile.ps1" -Destination "\\replaced-with-targetcomputer\C$\local" -Recurse
When i whant to call the script, i use the following:
Invoke-Command -ComputerName $ComputerName -ScriptBlock {C:\local\Repair_outlook_Profile.ps1}
However, above text provides me below error:
PS C:\Users\admin> Invoke-Command -ComputerName targetcomputer -ScriptBlock {C:\local\Repair_outlook_Profile.ps1}
[targetcomputer] Connecting to remote server targetcomputer failed with the following error message : WinRM cannot
complete the operation. Verify that the specified computer name is valid, that the computer is accessible over the
network, and that a firewall exception for the WinRM service is enabled and allows access from this computer. By
default, the WinRM firewall exception for public profiles limits access to remote computers within the same local
subnet. For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (clienttarget:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : WinRMOperationTimeout,PSSessionStateBroken
i want to avoid them using powershell, as its not the idea of this button.
in the script itself, it does not copy the file to the target computer, it does not run the script using the invoke command.
Is this blocked by company firewall?
Do i have something wrong in my code?
An example button that works without any problem is:
$button_DriverQuery_Click={
$button_DriverQuery.Enabled = $False
Get-ComputerTxtBox
$DriverQuery_command="cmd.exe"
$DriverQuery_arguments = "/k driverquery /s $ComputerName"
Start-Process $DriverQuery_command $DriverQuery_arguments
$button_DriverQuery.Enabled = $true
}
Only this aditional button does not work. And i cannot figure it out at the moment.
What am i doing wrong here?
thank you.

Enumerating local groups using Invoke-Command on remote machines

I have an issue with a function I've wrote to return members of local groups when it is run against a remote machine. We use secondary domain accounts for admin privileges so I've used Invoke-Command so we can run the script block with that account, however, when I do this as opposed to running a new PowerShell window with my admin credentials, it can't enumerate members of the local group that aren't local users.
$computers = "blah"
$creds = Get-Credential
$sb = {
param($c)
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
$ctype = [System.DirectoryServices.AccountManagement.ContextType]::Machine
$context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList $ctype,$c
$idtype = [System.DirectoryServices.AccountManagement.IdentityType]::SamAccountName
$lg = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context,$idtype,"administrators")
$members = $lg.Members
return $members
}
foreach ($c in $computers) {
if ($c -eq $env:COMPUTERNAME) { & $sb -c $c }
else {
Invoke-Command -ComputerName $c -Credential $creds -ScriptBlock $sb -ArgumentList $c
}
}
When run against a machine that I'm logged in to locally it returns all members of the local group. It also works if I start a new console with my second account. If credentials are passed with Invoke-Command though, I receive errors pertaining to a lack of network access and it appears to happen after successfully listing the two local accounts on a machine first.
Information returned for lg variable when failing:
PSComputerName : blah
RunspaceId : hex...
IsSecurityGroup : True
GroupScope : Local
Members : {local_admin, local_user}
Context : System.DirectoryServices.AccountManagement.PrincipalContext
ContextType : Machine
Description : Administrators have complete and unrestricted access to the computer/domain
DisplayName :
SamAccountName : Administrators
UserPrincipalName :
Sid : SID...
Guid :
DistinguishedName :
StructuralObjectClass :
Name : Administrators
When it's successful, the Members section includes domain groups and users too (identical results if remotely with shell run as second account or locally on the server logged on as second account):
IsSecurityGroup : True
GroupScope : Local
Members : {local_admin, local_user, domain_group, domain_group, domain_user...}
Context : System.DirectoryServices.AccountManagement.PrincipalContext
ContextType : Machine
Description : Administrators have complete and unrestricted access to the computer/domain
DisplayName :
SamAccountName : Administrators
UserPrincipalName :
Sid : SID...
Guid :
DistinguishedName :
StructuralObjectClass :
Name : Administrators
Two different errors received with slightly different approaches:
An error occurred while enumerating through a collection: The network path was not found.
.
+ CategoryInfo : InvalidOperation: (System.Director...ctionEnumerator:PrincipalCollectionEnumerator) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
+ PSComputerName : blah
Cannot convert value "System.DirectoryServices.AccountManagement.PrincipalCollection" to type "System.Array". Error: "The network path was not found.
"
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
+ PSComputerName : blah
The first message is from just trying to return the members variable, the second one was when I tried to make that variable an array. I think they essentially have the same root cause. I tried adding the -EnableNetworkAccess switch to Invoke-Command, but this doesn't change the error received.
I appreciate that I already know a way to make this work, but we'd like to see if there is any way around running the shell with admin credentials and only introducing them when they need to be passed for remote servers. It doesn't appear to be an authentication issue because we can run more simple commands using Invoke-Command i.e. ipconfig or whoami.
I'm using PowerShell 5.1
Thanks.
PoSH remoteing requires the account to be a local admin on the target host, with the exception of the commands listed below. Is this...
'We use secondary domain accounts for admin privileges'
... a local admin?
https://technet.microsoft.com/en-us/library/ff699046.aspx
Some cmdlets have a –ComputerName parameter that lets you work with a remote computer without using Windows PowerShell remoting. This means you can use the cmdlet on any computer that is running Windows PowerShell, even if the computer is not configured for Windows PowerShell remoting. These cmdlets include the following
If you are trying to remote across domain, you are going to get hit with the Windows double hop restriction and you'll need to plan and configure for that type of scenario. See the below.
https://blogs.msdn.microsoft.com/clustering/2009/06/25/powershell-remoting-and-the-double-hop-problem
An Easy “Double-Hop” Solution
You can use CredSSP to delegate your credentials to the remote computer so every remote access from the remote machine will also work. To enable this, you will need to run (from an elevated command prompt) the following command on the client machine:
Or this option...
https://blogs.technet.microsoft.com/ashleymcglone/2016/08/30/powershell-remoting-kerberos-double-hop-solved-securely
Are you facing issues with PowerShell remoting and credentials? You remote into your jump box, but then any remoting beyond there gets a big red ACCESS DENIED. Maybe you’ve tried CredSSP, but people say that isn’t safe. Read today’s post for a completely legit, secure, safe, and easy way to enable Kerberos double hop for PowerShell remoting.

"Access denied" error when trying to enumerate drives on remote computers

I am trying to run a PowerShell command to get the total disk space of all drives for all our remote servers. When I run the command I am getting the error below. I have a text file which has names of the servers and I have also confirmed that WinRM is configured and is running.
$Servers = Get-Content "C:\users\anorris\desktop\DR\servers1.txt"
foreach ($s in $Servers) {
Invoke-Command -ComputerName $s {Get-PSDrive}
}
Error:
[ahv-a2acortst02] Connecting to remote server failed with the following error
message : Access is denied.
For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (:) [], PSRemotingTransportException
+ FullyQualifiedErrorId : PSSessionStateBroken
Agreed that the message 'Access is denied' is a dead giveaway that you don't have access.
I would create a credential variable and make sure it is a credential that has rights to the remote system.
$Creds = Get-Credential
then change your code to the following (I added the -scriptblock and the bolded text
$Servers = Get-Content "C:\users\anorris\desktop\DR\servers1.txt"
foreach ($s in $Servers) {
Invoke-Command -ComputerName $s -ScriptBlock {Get-PSDrive} -Credential $creds
}

How to remotely change a service account password on multiple servers

I've been searching through the archives here but haven't quite found a simple (ie: something I can understand) solution to my problem. I am changing passwords on service accounts using powershell and wmi. I can change the services one at a time across all servers like so:
$Service = Get-WmiObject -Class Win32_Service -computer REMOTESERVER -filter "name='SERVICENAME'"
$service.change($null,$null,$null,$null,$null,$null,$null,"newpasswordhere")
As you can see, I can refer to whatever server I want and whatever service on that server. What I'd like to do is the following
Provide a list of servers (a text file with "REMOTESERVER1,REMOTESERVER2" or something similar
Change the password for multiple services on the same machine that are running under the same credentials. I was able to get a list of mutliple services using -filter "StartName LIKE '%\MYSERVICEACCOUNT'", but when I then try to run the $service.change to update the password, I get an error
Method invocation failed because [System.Object[]] doesn't contain a method named 'change'.
At line:1 char:16
+ $service.change <<<< ($null,$null,$null,$null,$null,$null,$null,"newpasswordhere")
+ CategoryInfo : InvalidOperation: (change:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
It works fine with only one service though
Restart services only if they are already running
How can I enhance this script to handle these 3 additional items?
Thank you
You would want to add a loop to your above script, and you would want
param
(
[string]$File
)
$Computer = Get-Content $file
foreach ($i in $Computer){
$Service = Get-WmiObject -Class Win32_Service -computer $i -filter "name='SERVICENAME'"
$service.change($null,$null,$null,$null,$null,$null,$null,"newpasswordhere")
}
You add the Param so you can utilize this many different times, then the foreach loop will run through your code for each computer in your .txt file.
Now this only answers the first part of your question but should give you a good starting point.