I'm new to powershell and can't figure why I get the following error
Invoke-Command : A positional parameter cannot be found that accepts argument
'D:\Deploy\file.zip'.
At D:\source\Scripts\Build-Deploy\Build-Deploy\ServersDeploy.ps1:105 char:5
Invoke-Command -ComputerName $servers -ScriptBlock {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeCommandCommand
This is the script being run
params([string[[]]$servers, [string]$dest_package_path, [string]$src_package_path,[string]$deploy_script)
Invoke-Command -ComputerName $servers -ScriptBlock {
param($dest_package_path,$src_package_path,$deploy_script)
Write-Output "Destination path = $dest_package_path"
Write-Output "Copying zip $src_package_path to the destination host"
New-Item -ItemType Directory -Force -Path $dest_package_path
Write-Output "Directory Created"
Copy-Item -Path $src_package_path -Destination $dest_package_path -Force
Write-Host "Copying remote deploy scripts to the destination host"
Copy-Item -Path $deploy_script -Destination $dest_package_path -Force
} -ArgumentList $dest_package_path $src_package_path $deploy_script
Because you separated the arguments with spaces instead of a comma. That makes them new arguments to Invoke-Command.
-ArgumentList a single parameter that takes an array:
Invoke-Command -ComputerName $servers -ScriptBlock {
# Stuff
} -ArgumentList $dest_package_path,$src_package_path,$deploy_script
Related
Working remotely works fine -- mostly. Occasionally, I need to copy large files, or large numbers of files, from one server to another or from a vendor's web site to a server (like install sets). With limited upload speeds through the ISP I use at home, anything that involves large uploads will take a very long time.
It seems PowerShell's ability to run commands remotely should be able to help with this. I'm trying to create a simple app that will enable me to use another computer to copy from anywhere to anywhere (assuming I have appropriate permissions in all 3 places).
I like Start-BitsTransfer because it seems to be much faster and because I can use it to download software from a vendor's web site.
I have created a very simple example that I haven't been able to get to work.
If I log onto "server1" using Remote Desktop and do...
$src = "\\server2\c$\myfolder\*"
$dest = "c:\myfolder\"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest
...it works fine. All of the files from c:\myfolder on server2 are copied to c:\myfolder on server1.
Trying to remove Remote Desktop from the equation, here's what I have so far:
#RemoteCopy.ps1
param(
[string]$computer,
[string]$source,
[string]$destination
)
Invoke-Command -ComputerName $computer -ScriptBlock {
$src = $args[0]
$dest = $args[1]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest
#Copy-Item -Path $src -Destination $dest
} -ArgumentList $source,$destination
From my workstation:
.\RemoteCopy.ps1 -computer server1 -source "\\server2\c$\myfolder\*" -destination "c:\myfolder\"
But nothing happens.
Since I'm logged onto the network on my workstation, there shouldn't be a credential problem. If there was, I would expect to receive an error message.
For this specific example, my workstation, server1, and server2 are on the same domain and my user account is an admin on all three machines.
I'm currently using PowerShell 5.1.
Responding to comments
$Credential = Get-Credential
Invoke-Command -ComputerName $computer -ScriptBlock {
$src = $args[0]
$dest = $args[1]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest
#Copy-Item -Path $src -Destination $dest
} -ArgumentList $source,$destination -Credential $Credential
...behaves the same.
$Credential = Get-Credential
Invoke-Command -ComputerName $computer -ScriptBlock {
$src = $args[0]
$dest = $args[1]
$cred = $args[2]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest -Credential $cred
#Copy-Item -Path $src -Destination $dest
} -ArgumentList $source,$destination,$Credential -Credential $Credential
...produces an error:
The operation being requested was not performed because the user has not logged on to the network. The specified service does not
exist. (Exception from HRESULT: 0x800704DD)
+ CategoryInfo : NotSpecified: (:) [Start-BitsTransfer], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.BackgroundIntelligentTransfer.Management.NewBits
TransferCommand
+ PSComputerName : server1
Invoke-Command -ComputerName $computer -ScriptBlock {
$src = $args[0]
$dest = $args[1]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest -Credential domain\username
#Copy-Item -Path $src -Destination $dest
} -ArgumentList $source,$destination -Credential domain\username
...produces the same error
And if I try to follow https://www.ipswitch.com/blog/the-infamous-double-hop-problem-in-powershell (the first link on https://duckduckgo.com/?q=%27powershell+doublehop%27&t=h_&ia=web) ...
Invoke-Command -ComputerName $computer -ScriptBlock {
Register-PSSessionConfiguration -Name RemoteCopy -RunAsCredential 'domain\username' -Force
}
Invoke-Command -ComputerName $computer -ScriptBlock {
$src = $args[0]
$dest = $args[1]
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $src -Destination $dest -Credential domain\username
} -ArgumentList $source,$destination -ConfigurationName RemoteCopy.
...I get different errors:
Processing data for a remote command failed with the following error message: The I/O operation has been aborted because of either a thread exit or an application request. For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OperationStopped: (server1:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : JobFailure
+ PSComputerName : server1
[server1] Connecting to remote server server1 failed with the following error message : The WS-Management service
cannot process the request. Cannot find the RemoteCopy. session configuration in the WSMan: drive on the server1 computer.
For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (server1:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : InvalidResourceUri,PSSessionStateBroken
And if I remove the . from the end of the ConfigurationName argument in the Invoke-Command call, I get the same error I saw at the start of this rework:
The operation being requested was not performed because the user has not logged on to the network. The specified service does not exist. (Exception from HRESULT: 0x800704DD)
+ CategoryInfo : NotSpecified: (:) [Start-BitsTransfer], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.BackgroundIntelligentTransfer.Management.NewBits
TransferCommand
+ PSComputerName : server1
I also read https://www.codeproject.com/Tips/847119/Resolve-Double-Hop-Issue-in-PowerShell-Remoting. But other reading indicates the CredSSP is not secure. Credentials can be stolen. So I'd need to run this one by my security and infrastructure experts.
If this is a problem with credentials (that for some reason doesn't generate any error messages), how would I get through that?
I want to deploy Updates to Windows Servers in Our Domain.
To achieve this i want to use the Module "PSWindowsUpdate" Here is the Official Release.
I use this Module in combination with PSSessions and import it locally on all Servers outside of the default Module Path.
It should accept the updates and install them without rebooting. This Script is run using an Domain Administrator
After it Accepts the Updates it should start downloading where this happens: The Error of the Job
I started getting this error after the 2018 July Security Patch installed.
As I can't share all of the code because of Company reasons, here is the part that matters:
function invokeUpdate{
param(
$session
)
if($Script:My.Reboot.isChecked){
$job = Invoke-Command -Session $session -ScriptBlock {Import-Module "C:\Scripts\updateModule\$($Using:My.ModuleVersion)\PSWindowsUpdate"; get-windowsupdate -install -AcceptAll} -AsJob
}else {
$job = Invoke-Command -Session $session -ScriptBlock {Import-Module "C:\Scripts\updateModule\$($Using:My.ModuleVersion)\PSWindowsUpdate"; get-windowsupdate -install -ignoreReboot -AcceptAll} -AsJob
}
return $job
}
function initSession{
param(
$serverHostname
)
$ses = New-PSSession -Computername $serverHostname
if(!(Invoke-Command -Session $ses -ScriptBlock {Test-Path "C:\Scripts\updateModule\" })){
Copy-Item "$modpath\$($Script:My.ModuleVersion)" -Destination "C:\Scripts\updateModule\$($Script:My.ModuleVersion)" -ToSession $ses -Recurse
}
Invoke-Command -Session $ses -ScriptBlock {
if((Get-ChildItem -Path "C:\Scripts\updateModule\").count -gt 1){
Get-ChildItem | Where-Object Name -NotLike "$($Using:My.ModuleVersion)" | Remove-Item -Recurse -Force
}
}
return $ses
}
$sessions = [System.Collections.ArrayList]#()
$Script:My.ModuleVersion = "2.1.1.2"
foreach ( $server in $Script:My.ServerActive.Items){
$sessions.Add( (initSession -serverHostname $server) )
}
foreach ($ses in $sessions){
invokeUpdate -session $ses
}
$Script:My.ServerActive.Items :
contains a list of server fqdns
Any Ideas or Solutions would save me,
thanks!
Nik
Edit 1:
Here is the Error Message:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
+ CategoryInfo : NotSpecified: (:) [Get-WindowsUpdate], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,PSWindowsUpdate.GetWindowsUpdate
+ PSComputerName : fs02.azubi.netz
This will break my Sessions, but the output is $true
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
Invoke-Command : Cannot bind parameter 'Session'. Cannot convert value "True" to type "System.Management.Automation.Runspaces.PSSession". ...
To Fix This Problem I had to change the way of Copying to the other System and the Actual call of get-windowsupdate.
The Mooudle has to be in $env:PSModPath, so to fix it you have to copy into one of those folders.
Copy-Item "$modpath\$($Script:My.ModuleVersion)\" -Destination "$psmod\PSWindowsUpdate\$($Script:My.ModuleVersion)" -ToSession $ses -Recurse -ErrorAction Stop
the Update doesnt need to run Over Invoke Command.
Get-WindowsUpdate -AcceptAll -Install -IgnoreReboot -ComputerName $session.ComputerName
Hope this will Help if you get a similar Problem!
I have Text file with number of local VM names in Hyper-v :
newname
IL-SRV
IL-TST
IL-MGN
IL-BBT
This is the names in my hyper-V environment , And i would like to change their computer name by using Powershell and bulk
I'm using this script
$computers = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($newname in $computers){
Invoke-Command -VMName $computers.newname -Credential administrator -ScriptBlock {Rename-Computer -NewName $computers.newname -Restart -Force}
}
But i receive this error
"
Invoke-Command : The input VMName IL-SRV does not resolve to a single virtual machine.
At line:11 char:1
+ Invoke-Command -VMName $computers.newname -Credential administrator - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : InvalidVMNameNotSingle,Microsoft.PowerShell.Commands.InvokeCommandCommad
"
Each iteration you are processing the entire list of $computers.newname
In your loop you create variable $newname without ever using it. You should be very careful when running commands that make changes especially if you aren't familiar with how powershell works. The other glaring issue is you are using Invoke-Command on a remote computer but using a local variable. I am taking a guess that you're trying to do is this.
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($line in $CSVData){
Invoke-Command -VMName $line.newname -Credential administrator -ScriptBlock {Rename-Computer -NewName $using:line.newname -Restart -whatif}
}
Note the $using:line variable. This provides the contents of the local variable to the remote computer. Another way to handle it would be use the -Argumentlist. I recommend using named parameters when doing so, like this.
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($line in $CSVData){
Invoke-Command -VMName $line.newname -Credential administrator -ScriptBlock {
Param($incomingname)
Rename-Computer -NewName $incomingname -Restart -whatif
} -ArgumentList $line.newname
}
The last thing you need to do AFTER confirming it's going to do what you desire is to remove the -WhatIf parameter from Rename-Computer. Rename-Computer has a -ComputerName parameter as well, fyi.
Either of these could also be written like this since there is only one property on $CSVData that we care about
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($name in $CSVData.newname){
Invoke-Command -VMName $name-Credential administrator -ScriptBlock {Rename-Computer -NewName $using:name -Restart -whatif}
}
or
$CSVData = import-csv -Path C:\Users\Itay\Desktop\Servers.txt
foreach ($name in $CSVData.newname){
Invoke-Command -VMName $name -Credential administrator -ScriptBlock {
Param($incomingname)
Rename-Computer -NewName $incomingname -Restart -whatif
} -ArgumentList $name
}
I have a windows service running on one of the Azure VMs.
So whenever a deployment has to be done, we copy the binaries manually. So now, I'm writing a script to do that.
Besically the binaries are in the form of a zip folder in MachineA. That zip folder is copied to MachineB (where windows service is running).After copying, the files are extracted and then zip folder is deleted. Then after the service is started.
To do this I have the below script.
#get session details
$UserName = "$IPAddress\$adminUsername"
$Password = ConvertTo-SecureString $adminPassword -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($UserName, $Password)
$s = New-PSSession -ComputerName $IPAddress -Credential $psCred
#stop the service
Invoke-Command -Session $s -ScriptBlock {Stop-Service -Name "ServiceName" -Force}
#delete existing binaries in destination machine
$tempDestPath = $destinationPath + "\*"
Invoke-Command -Session $s -ScriptBlock {param($tempDestPath)Remove-Item $tempDestPath -Recurse} -ArgumentList $tempDestPath
#copy binaries zip folder in destination machine
Copy-Item -Path $sourcePath -Destination $destinationPath -ToSession $s -Recurse
#extract zipfolder in destination machine
$zipFilePath = $destinationPath + "\" + $fileName
Invoke-Command -Session $s -ScriptBlock {param($zipFilePath,$destinationPath) Expand-Archive $zipFilePath -DestinationPath $destinationPath}-ArgumentList $zipFilePath,$destinationPath
#delete zipfolder in destination machine after extraction
Invoke-Command -Session $s -ScriptBlock {param($zipFilePath)Remove-Item –path $zipFilePath}-ArgumentList $zipFilePath
#start the service
Invoke-Command -Session $s -ScriptBlock {Start-Service -Name "ServiceName"}
This is working fine when I open Windows powershell in MachineA and execute these commands one by one.
But when I put the exact same commands in a ps1 file and execute that file, I'm getting the below error:
At C:\ScriptTest\test.ps1:13 char:95
+ ... -ScriptBlock {Start-Service -Name "ServiceName"}
+ ~~
The string is missing the terminator: ".
At C:\ScriptTest\test.ps1:11 char:42
+ Invoke-Command -Session $s -ScriptBlock {param($zipFilePath)Remov ...
+ ~
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
Where am I missing this terminator. I'm not able to figure out. Any help is highly appreciated.
Turns out a - in one of the commands is wrong.
I have replaced this line
Invoke-Command -Session $s -ScriptBlock {param($zipFilePath)Remove-Item –path $zipFilePath}-ArgumentList $zipFilePath
with this line
Invoke-Command -Session $s -ScriptBlock {param($zipFilePath)Remove-Item -path $zipFilePath}-ArgumentList $zipFilePath
The hyphen in from of the path is slightly different.I was able to figure out from this answer
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
}