How to create registry on multiple remote machine - powershell

I'm creating a registry key on remote machine with below code:
$basePath="C:\Users\<User>\Desktop\Script\"
$remoteMachineName = $basePath + "server.txt"
$arrServer=(Get-Content $remoteMachineName)
$remoteUserPassword = Get-Content "C:\Users\<UserName>\Desktop\Script\pass.txt"
ConvertTo-SecureString -AsPlainText -Force -String $password
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "UserName"
Enter-PSSession -ComputerName $server -Credential $credentials
New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType "String" -Path "HKLM:\SOFTWARE\Usertest"
But it creates registry key on my local machine however I want it on remote machine giving below error :
New-ItemProperty : The property already exists.
At C:\Users\<User>\Desktop\Script\Untitled4.ps1:14 char:1
+ New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceExists: (HKLM:\SOFTWARE\Usertest\:String) [New-ItemProperty], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.NewItemPropertyCommand
But when I run command Enter-PSSession and New-ItemProperty separately it works but I want to run both the commands simultaneously.
Please Help me to create registry Key on remote machine.

Just use the Invoke-Command cmdlet:
# ...
Invoke-Command -cn $server -cred $credentials {
New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType "String" -Path "HKLM:\SOFTWARE\Usertest" -Force
}

Related

A positional parameter cannot be found that accepts argument-System.Management.Automation.PSCredential'-Error

I have a script which needs to run from remote by passing on credentials in the script as as below:-
$UserName = Read-Host "Enter User Name:"
$Password = Read-Host -AsSecureString "Enter Your Password:"
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $UserName , $Password
Set-Service -Name HiTrust -StartupType Automatic -ComputerName ServerName -credential $Credential
(Get-Service -Name "HiTrust" -credential $Credential -ComputerName ServerName).Start()
Exit
However I keep on getting error as below:-
Set-Service : A positional parameter cannot be found that accepts argument 'System.Management.Automation.PSCredential'.
At C:\Users\ucub\Desktop\Test.ps1:9 char:15
+ ... Set-Service -Name HiTrust -StartupType Automatic -Compute ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-Service], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.SetServiceCommand
If you are on this PSVersion and below, here is your root cause of why this fails on Set-Service...
$PSVersionTable.PSVersion
<#
Major Minor Build Revision
----- ----- ----- --------
5 1 17763 503
#>
(Get-Command -Name Set-Service).Parameters.Keys
# Results
ComputerName
Name
DisplayName
Description
StartupType
Status
InputObject
PassThru
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
WhatIf
Confirm
You have unneeded stuff in the script as well.
I suggest refactoriung to this
(Get-Command -Name Invoke-Command).Parameters.Keys
# Results
Session
ComputerName
Credential
...
$ServerName = Read-Host 'Enter a target server name:'
$ServiceName = Read-Host 'Enter a target service name:'
Invoke-Command -ComputerName $ServerName -ScriptBlock {
"Executing service actions on $env:COMPUTERNAME"
Set-Service -Name $ServiceName -StartupType Automatic
Start-Service -Name $ServiceName
} -Credential (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME")
The Problem is, that set-service doesn't have a credential parameter. Look here
Try something like this:
Enter-PSSession -ComputerName $computername -Credential $credentials
Set-Service -Name HiTrust -StartupType Automatic
or
Invoke-Command -ComputerName $computername -Credential $credential -ScriptBlock {Set-Service -Name HiTrust -StartupType Automatic}

PowerShell Issue regarding entering a PS Session and setting permissions

I am currently making a script to create a folder which then creates an AD group and links them together. I then connect to our server in the data centre to set the permissions.
To do this I need to enter a PSSession and find the folder and set the permissions. Unfortunately, it's not working. Any help would be appreciated.
Script
#Get ADM Credentials
$Cred = Get-Credential
# PowerShell's New-Item creates a folder
$Name = Read-Host "What is the name of the folder?"
$Location = Read-Host "What is the folder path? i.e B:\Collaboration\"
New-Item -Path $Location -Name $Name -ItemType "directory"
#Invoke-Item $Location
# Powershell creates an AD group
$Groupname = Read-Host "What is the group name? i.e. SS COLLABORATION BEN"
New-ADGroup -path "OU=StorSimple Centralisation Groups,OU=Groups,OU=Northgate PLC,DC=northgatevehiclehire,DC=net" -Name $Groupname -GroupCategory Security -GroupScope Global -DisplayName $Groupname -Description "Access to $Location" -Credential $cred
#Connect to StudFS01
$Folderpath = Read-Host "What is the path of the folder in StudFS e drive? i.e. Vehicle Sales\TOM Information"
Enter-PSSession -ComputerName Studfs01 -Credential $Cred
Start-Sleep -Seconds 10
Set-Location -Path E:\CentralisedData\Data\$folderpath
#Set Permissions
$rule=new-object System.Security.AccessControl.FileSystemAccessRule ("northgatevehiclehire.net\Domain Admins","FullControl","Allow")
$rule2=new-object System.Security.AccessControl.FileSystemAccessRule ("northgatevehiclehire.net\StorSimple Centralisation Administrators","FullControl","Allow")
$rule3=new-object System.Security.AccessControl.FileSystemAccessRule ("$Groupname","Modify","Allow")
$acl = Get-ACL E:\CentralisedData\Data\$folderpath
$acl.SetAccessRule($rule,$rule2,$rule3)
Set-ACL -Path E:\CentralisedData\Data\$folderpath -AclObject $acl
Error Im getting is below
Set-Location : Cannot find drive. A drive with the name 'E' does not exist.
At C:\Users\ben.curtis-haigh\Documents\New Security Group Script.ps1:19 char:1
+ Set-Location -Path E:\CentralisedData\Data\$folderpath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (E:String) [Set-Location], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SetLocationCommand
Get-ACL : Cannot find drive. A drive with the name 'E' does not exist.
At C:\Users\ben.curtis-haigh\Documents\New Security Group Script.ps1:25 char:8
+ $acl = Get-ACL E:\CentralisedData\Data\$folderpath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (E:String) [Get-Acl], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetAclCommand
You cannot call a method on a null-valued expression.
At C:\Users\ben.curtis-haigh\Documents\New Security Group Script.ps1:26 char:1
+ $acl.SetAccessRule($rule,$rule2,$rule3)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Set-Acl : Cannot bind argument to parameter 'AclObject' because it is null.
At C:\Users\ben.curtis-haigh\Documents\New Security Group Script.ps1:27 char:62
+ Set-ACL -Path E:\CentralisedData\Data\$folderpath -AclObject $acl
+ ~~~~
+ CategoryInfo : InvalidData: (:) [Set-Acl], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.SetAclCommand`
Thanks
Instead of Enter-PSSession which is meant for interactive use, you need to establish a new PSSession and then use Invoke-Command against it. Something like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ScriptBlock {
<CODE TO EXECUTE ON REMOTE SYSTEM HERE>
}
If you need to pass parameters/variables, you have two choices. The easiest (in newer versions of PowerShell) is the using statement like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ScriptBlock {
Set-Location -Path E:\CentralisedData\Data\$using:Folderpath
}
Another option is to pass your arguments with -ArgumentList and use Param() in the script block like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ArgumentList $Folderpath -ScriptBlock {
Param($Folderpath)
Set-Location -Path E:\CentralisedData\Data\$Folderpath
}
Instead of Enter-PSSession which is meant for interactive use, you need to establish a new PSSession and then use Invoke-Command against it. Something like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ScriptBlock {
<CODE TO EXECUTE ON REMOTE SYSTEM HERE>
}
If you need to pass parameters/variables, you have two choices. The easiest (in newer versions of PowerShell) is the using statement like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ScriptBlock {
Set-Location -Path E:\CentralisedData\Data\$using:Folderpath
}
Another option is to pass your arguments with -ArgumentList and use Param() in the script block like this:
$PSSession = New-PSSession -ComputerName Studfs01 -Credential $Cred
Invoke-Command -Session $PSSession -ArgumentList $Folderpath -ScriptBlock {
Param($Folderpath)
Set-Location -Path E:\CentralisedData\Data\$Folderpath
}

Copy-Item throws AccessDenied exception

I am trying to copy files from a remote server to my base machine using powershell. This throws an 'Access Denied' exception even though the drives get mapped:
New-PSDrive -Name source -PSProvider FileSystem -Root "\\SERVERNAME1\D$\Temp\Folder" ;
New-PSDrive -Name target -PSProvider FileSystem -Root $destinationRemotePath ;
Copy-Item -Path source:\$($file).zip -Destination target: -Verbose -ErrorAction Stop -Force ;
Approach 2
I am mapping the source drive and using PsSession for target drive but I get
Cannot find drive. A drive with the name 'source' does not exist.
+ CategoryInfo : ObjectNotFound: (source:String) [Copy-Item], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
Following is the code being used:
$Username = "UserName";
$Password = ConvertTo-SecureString "Password" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username, $Password)
$session = new-pssession -computername 'TargetServerName' -credential $cred
New-PSDrive -Name source -PSProvider FileSystem -Root "\\SERVERNAME1\D$\Temp\Folder" ;
Invoke-Command -Session $session -ScriptBlock { Copy-Item -Path $($args[0]) -Destination $($args[1]) -Verbose -ErrorAction Stop } -ArgumentList source:\$($file).zip,'D:\Folder' ;
There are some issues on that second example:
The PSSession has a different scode, it does not know about your PSDrive.
PSSessions do not support authentication to network location like you might be used to from RDP-Sessions. See CredSSP or ' PSSession double hop'
Approach 1 looks like you have no access to that share you want to use. You can specify credentials via -Credential parameter at New-PSDrive. Can you Get-Childitem on Source: and Target:?

Run Reg.exe in PS script will not work on remote machine ERROR: Invalid key name

If I run the command from with in the script
reg add "HKU\$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v AutoConfigURL /t REG_SZ /d "http://mydomaon.com/proxies/proxy.pac" /f
it works perfectly, because it is local.
When I try to change the same registry key on a remote machine and changing the line to this
reg add "\\$machinename\HKU\$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v AutoConfigURL /t REG_SZ /d "http://mydomaon.com/proxies/proxy.pac" /f
It fails with
ERROR: reg : ERROR: Invalid key name. + CategoryInfo : NotSpecified: (ERROR: Invalid key name.:String) [], RemoteException
ERROR: + FullyQualifiedErrorId : NativeCommandError
ForEach ($machine in $machines)
{
$User = New-Object System.Security.Principal.NTAccount($env:UserName)
$sid = $User.Translate([System.Security.Principal.SecurityIdentifier]).value
New-PSDrive HKU Registry HKEY_USERS
# Get-Item "HKU:\${sid}"
Set-Location HKU:\
cd HKU:\
reg add '$SID\Software\Microsoft\Windows\CurrentVersion\Internet Settings' /v AutoConfigURL /t REG_SZ /d 'http://proxy.domain.com/proxies/proxy.pac' /f
}
Here is an approach that should work (also better then using reg.exe):
Local Computer:
New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS
New-ItemProperty -Path "HKU:\$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name AutoConfigURL -PropertyType String -value "http://proy.domain.com/proxies/proxy.pac" -Force
Remote Computer:
$credential = Get-Credential
Foreach($machine in $computers){
Invoke-Command -ComputerName $machine -Credential $credential -ScriptBlock {$temp = $args[0];
New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS; New-ItemProperty -Path "HKU:\$temp\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -PropertyType String -Name AutoConfigURL -Value "http://proy.domain.com/proxies/proxy.pac" -Force} -argumentlist $sid
}
Also here are the Type mappings for New-Itemproperty´s -PropertyType:
REG_SZ = String
REG_DWORD = DWord
REG_QWORD = QWord
REG_MULTI_SZ = MultiString
REG_BINARY = Binary
So after a few problems here is an updated version which should do everything including determining the local users sid by username (added linebreaks for readability, remove them when you copy)
$username = "yourUsername"
$credential = Get-Credential
Foreach($machine in $computers){
Invoke-Command -ComputerName $machine -Credential $credential -ScriptBlock {$temp = $args[0];
New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS;
$sid = (Get-CimInstance -Class Win32_UserAccount | where {$_.Name -eq $temp} | select SID).SID;
New-ItemProperty -Path "HKU:\$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -PropertyType String -Name AutoConfigURL -Value "http://proy.domain.com/proxies/proxy.pac" -Force
} -argumentlist $username
}
After furhter discussion with Kent and clearly specifying the environment (Windows XP domain-joined machines, user logged on) the script has to run in this was what we came up with:
(this works only if the user is logged in on XP)
$sid = ((get-aduser $username).SID).Value
$credential = Get-Credential
Foreach($machine in $computers){
Invoke-Command -ComputerName $machine -Credential $credential -ScriptBlock {New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS; New-ItemProperty -Path "HKU:\$($args[0])\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -PropertyType String -Name AutoConfigURL -Value "http://proxy.domain.com/proxies/proxy.pac" -Force} -argumentlist $sid
}
This is how it would work if the user was not currently log in on XP:
$defaultprofilepath = "C:\documents and settings"
$username = "username"
$profilepath = "$defaultprofilepath\$username"
$credential = Get-Credential
Foreach($machine in $computers){
Invoke-Command -ComputerName $machine -Credential $credential -ScriptBlock {reg load "HKU\TempDir" "$($args[0])\NTUSER.DAT"; reg add "HKU\TempDir\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v AutoConfigURL /t REG_SZ /d 'http://proxy.domain.com/proxies/proxy.pac' /f; reg unload "HKU\TempDir"} -argumentlist $profilepath
}
P.S. If someone has a clue if there is a powershell cmdlet to load registry hives please comment, i could not find one on the fly
Using WMI you could do it like this:
$computers = ...
$user = New-Object Security.Principal.NTAccount($env:USERNAME)
$sid = $user.Translate([Security.Principal.SecurityIdentifier]).Value
$subkey = "$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
$url = 'http://proy.domain.com/proxies/proxy.pac'
$HKU = [convert]::ToUInt32('0x80000003', 16)
$credential = Get-Credential
foreach ($machine in $computers) {
$reg = Get-WmiObject -List -Namespace 'root/default' -Computer $machine `
-Credential $credential | ? { $_.Name -eq 'StdRegProv' }
$reg.SetStringValue($HKU, $subkey, 'AutoConfigURL', $url) | Out-Null
}
Note, however, that for remote WMI access you need administrative privileges on the remote host. Without admin privileges you could use Invoke-Command for local WMI access on the remote host:
foreach ($machine in $computers) {
Invoke-Command -Computer $machine -Credential $credential -ScriptBlock {
$reg = Get-WmiObject -List -Namespace 'root/default' |
? { $_.Name -eq 'StdRegProv' }
$reg.SetStringValue($args[0], $args[1], 'AutoConfigURL', $args[2]) | Out-Null
} -ArgumentList $HKU, $subkey, $url
}
Note also that only domain accounts have the same SID accross hosts. For local accounts you need to determine the SID of the account on the remote host:
foreach ($machine in $computers) {
Invoke-Command -Computer $machine -Credential $credential -ScriptBlock {
$user = New-Object Security.Principal.NTAccount($args[0])
$sid = $user.Translate([Security.Principal.SecurityIdentifier]).Value
$subkey = "$sid\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
$reg = Get-WmiObject -List -Namespace 'root/default' |
? { $_.Name -eq 'StdRegProv' }
$reg.SetStringValue($args[1], $subkey, 'AutoConfigURL', $args[2]) | Out-Null
} -ArgumentList $env:USERNAME, $HKU, $url
}
If the account in question is a domain account, you may want to provide the domain name when creating the NTAccount object, because otherwise you'd be getting the wrong account/SID when there's a local account with the same name as the domain account.
$user = New-Object Security.Principal.NTAccount($env:USERDOMAIN, $env:USERNAME)
$sid = $user.Translate([Security.Principal.SecurityIdentifier]).Value

Powershell OnlyInJobError

Weird problem I saw today and I don't understand.
Is there a difference beetween running a script manually in the ISE or Pshell, and as a job?
If I run it manually the code doesn't throw an error - runs smoothly:
Get-ChildItem "\\SERVER\S$\ROOT\DIR" -Recurse | Where {$_.creationtime -lt (Get-Date).AddDays(-35)} | Remove-Item -Force -Include *.conf
But if I run it via Job and let the it export the $error to a txtfile this happens:
Are the rights of my running machine different to the rights of the scheduled job?
Get-ChildItem : Zugriff verweigert
In Zeile:81 Zeichen:1
+ Get-ChildItem "\\SERVER\S$\ROOT\DIR" -Recurse | Where
{$_.creati ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ChildItem], UnauthorizedA
ccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.Pow
erShell.Commands.GetChildItemCommand
Zugriff verweigert = Access denied
Oh, totally forgot to tell about my windows rights.
Normally the Server I am connecting to is blocked for everybody - except for login with credentials ofc. But somehow my manual powershell script is able to delete and create files?
In "job-mode" it loses it's abilities.
Edit:
Same for the Test-Path commandlet. Manually it shows me true or false. Via job it throws an error.
EDIT - SAME PROBLEM COMPLETELY DIFFERENT Commandlets:
$username = "Administrator"
$password = cat C:\securestring.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
New-PSDrive -Name Z -PSProvider FileSystem -Root \\Server\ROOT -Credential $cred -Persist
test-path 'Z:'
Remove-PSDrive -Name Z -PSProvider FileSystem
This works!
This does not:
$jobname = "Test5"
$JobTrigger = New-JobTrigger -Daily -At "00:18 PM"
$MyOptions = New-ScheduledJobOption -ContinueIfGoingOnBattery -HideInTaskScheduler -RunElevated
Register-ScheduledJob -name "$jobname" -scriptblock {
$username = "Administrator"
$password = cat C:\securestring.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
New-PSDrive -Name Z -PSProvider FileSystem -Root \\Server\ROOT -Credential $cred -Persist
test-path 'Z:'
Remove-PSDrive -Name Z -PSProvider FileSystem
} -trigger $JobTrigger –ScheduledJobOption $MyOptions
You probably have the job running under the SYSTEM account. Use the -Credential parameter to provide your account credentials (whatever account you're logged in with when you successfully run the command interactively).
BTW, Register-ScheduledJob uses the Task Scheduler. You can check the properties of the job in Task Scheduler to see what account it's configured to run as.
Well, it is not exactly an answere to my original question, but I was able to work around my problem by using the invoke-command and test-path from there and giving argument via the -arg.
Invoke-Command -ComputerName $FTPADRESS -ArgumentList $DIRECTORY -ScriptBlock {param ($DIR)
$check = Test-Path -Path "\\SERVER\ROOT\$DIR"
if ($check -ne $true) {New-Item -ItemType directory -Path "\\SERVER\ROOT\$DIR"}
}
Same works with the get-childitem.