I have read the Q/A already available and found no answer for my (maybe too simple?) case.
I have a PS function which:
1) put a local .bat file into a remote machine (target)
2) calls the remote .bat (through invoke-command) passing it a parameter
3) wait for the successful completion of the remote .bat
4) delete the .bat from the target machine
My problem is that everything runs perfectly but...the parameter is not displayed!
The code of the PS script is:
function Run-BatchFile ($computer,$dbn, [string]$batLocation)
{
$sessions = New-PSSession -ComputerName $computer -Credential elsmith
Copy-Item -Path $batLocation -Destination "\\$computer\C$\temp" #copy the file locally on the machine where it will be executed
$batfilename = Split-Path -Path $batLocation -Leaf
Invoke-Command -Session $sessions -ScriptBlock {param($batfilename) & cmd.exe /c "C:\Temp\$batfilename $dbn" } -ArgumentList $batfilename -AsJob
-ArgumentList $batfilename -AsJob
Get-job | Wait-Job
Remove-Item -Path "\\$computer\C$\Temp\$batfilename" -Force
Remove-PSSession -Session $sessions
}
Run-BatchFile SERVERNAME JOHN "C:\Temp\test_remote_called.bat"
The code of the invoked script is just:
set DB=%1
echo Test of %DB% was successful >> c:\temp\output.txt
exit /B
The output is:
Test of was successful
I'm sure there must be a trivial way to solve this problem: am I doing a gross mistake? Am I missing anything?
Related
invoke-command -scriptblock {powershell -File "D:\batch\Fix-4Log4J.ps1"} -computer $Server -AsJob -JobName "Scan4Log4J" -Verbose -EA SilentlyContinue
When I run this script locally, with enter-pssession the script works just fine but NO CSV
& D:\batch\Fix-4Log4J.ps1
Yet every time I try to invoke, directly or with SAPS it fails to create file
SYNTAX of EXE:
.\log4j2-scan.exe --force-fix d:\apps c:\users --report-csv --throttle 45
Now go and run it with NO other choices....
...and oh my goodness, I figured it out... :)
invoke-command -scriptblock {powershell -File "D:\batch\Fix-4Log4J.ps1"} -computer $Server -AsJob -JobName "Scan4Log4J" -Verbose -EA SilentlyContinue **get-job -name Scan4Log4J| receive-job -wait**
It was the receive-job that showed WHERE that BLASTED log went! HAH!
.\log\20220909.txt
WHEW!!!
I need to copy file from one remote server to other using powershell script.
What I have tried :-
While i use following powershell commands it's work fine.(means file copied from one server to other)
But while i use following script it gives error "cannot find path..." as follows
Actually, file is exist at that path.
I have tried to refer following stack-overflow already question-answer
Error with PowerShell command for copying file to remote server with credential
'Session' Parameter is null or empty in PowerShell script
powershell remote
Invoke-Command with remote session: Cannot validate argument on parameter
Unable to copy a binary to a remote Azure VM
PowerShell Command to Copy File on Remote Machine
I have also tried to get help using
Get-Help Invoke-Command
Question :-
How can i use "Copy-Item" command inside "Invoke-Command(Scriptblock)" in script(2) to copy file?
Is there any better way to achieve this(means best practice)?
Invoke-Command has the parameter -ArgumentList wich can be used to supply the values of local variables in the remote session. The Problem is: it's just the VALUE of the variable. No file!
What you can do:
Use Get-Content -Raw on small files to save the contant in a variable. On the target system create a New-Item with the -Value of that file. However thats not very efficent.
Example:
$txt = Get-Content -Raw -Path "C:\test\oldFile.txt"
$Session = New-PSSession 127.0.0.1
Invoke-Command -Session $Session -ScriptBlock { Param($Txt) New-Item -Path c:\test\newFile.txt -Value $txt } -ArgumentList $txt
#Get-PSSession | Remove-PSSession
Result:
Verzeichnis: C:\test # Sry german OS
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
-a---- 03.09.2020 12:23 658033 newFile.txt 127.0.0.1
What you should do:
I think your use of Copy-Item -ToSession $Session is the right way to do it. It's litteraly made just for your purpose. The downside is, that the target directory needs to exist. But you need a PSSession for both cmdlets anyway. So you can use Invoke-Command with the same PSSession. First Create a PSSession. Use Invoke-Command to create you directory. Then use Copy-Item to move your file to the right place. Finally you can use Invoke-Command to do some finishing steps. And don't forget to Remove-PSSession when you are done:
$DestinationPath = "C:\test"
Invoke-Command -Session $Session -ScriptBlock { Param($Destination) New-Item -Path $Destination -ItemType Directory } -ArgumentList $DestinationPath
Copy-Item -Path "C:\test\oldFile.txt" -ToSession $Session -Destination "c:\test\newFile.txt"
Invoke-Command -Session $Session -ScriptBlock { write-host "Do some stuff" }
$Session | Remove-PSSession
I'm using the following script to import a .reg file to remote computers. What I need to happen is the following:
Connect to the remote computer and kill a running process if it's running.
Copy a .reg key file from a Network Share location to the remote computer.
Import the copied .reg key to the remote computer's registry.'
Delete the copied .reg key file from the remote computer.
Start the process that was killed at the beginning.
Now I'm relatively new to PowerShell scripting and the script I have is part cannibalized from scripts I've found searching the internet and my PowerShell Cookbook.
What happens when I run the script is that it'll connect to the remote computer and kill the process, but then the script gets hung up, and doesn't do steps 2-5. It's not throwing out any errors either. What am I missing or doing wrong?
Thanks in advance!
#Variables
$Computers = Get-Content C:\computer.txt
$LocalRegFileName = "regfile.reg"
$HostedRegFile = "\\NETWORK-SHARE\Folder\Folder\regfile.reg"
$ProcessName = "Process"
$FilePath = "C:\Program Files (x86)\Folder\$ProcessName.exe"
foreach ($Computer in $Computers) {
Invoke-Command -ComputerName $Computer {
Get-Process -Name $ProcessName | Stop-Process -Force
}
$NewFile = "\\$Computer\C'$\TEMP\$LocalRegFileName"
New-Item -ErrorAction SilentlyContinue -ItemType directory -Path \\$Computer\C$\TEMP
Copy-Item $HostedRegFile -Destination $NewFile
Invoke-Command -ComputerName $Computer -ScriptBlock {
Start-Process -FilePath "C:\Windows\regedit.exe" -ArgumentList "/s C:\TEMP\$LocalRegFileName"
}
Invoke-Command -ComputerName $Computer -ScriptBlock {
Remove-Item "C:\TEMP\$LocalRegFileName"
}
Invoke-Command -ComputerName $Computer -ScriptBlock {
Start-Process -FilePath "$FilePath\$ProcessName.exe"
}
}
We have logfile on a server A in a different location (no UNC Path access) and we wish to copy the file to server B. This successfully works with Copy-Item -FromSession (run on Server B) as long as the file is closed. So we can successfully copy the previous day's logs but not today's.
$cred = Get-OurUserCredentials
$sess = New-PSSession -ComputerName $ServerA -Credential $cred -Authentication Negotiate
$LogFile = "D:\log\tomcat\access.20180227.log"
Copy-Item -FromSession $sess $LogFile "D:\logs\tomcat\" -Force
However, we can locally copy the active log of today if we run Copy-Item locally on server A. It's only Copy-Item -FromSession on server B which fails with:
Copy-Item : The process cannot access the file 'D:\log\tomcat\access.20180227.log' because it is being used by another process.
At line:11 char:2
As a workaround we could create a local task on server A to create a local copy but why is this necessary?
Why does Copy-Item behave differently when run remotely and can we "fix" it's behaviour so it copies the log remotely as it would locally.
A version of the answer proposed in the OP but avoiding the need for a scheduled task.
$cred = Get-OurUserCredentials
$sess = New-PSSession -ComputerName $ServerA -Credential $cred -Authentication Negotiate
#ScriptBlock to copy file locally
$SB =
{
#Create variables on the remote machine avoid havin gto pass to scriptblock
$LogFile = "D:\log\tomcat\access.20180227.log"
$TempDes = "temporarylocationhere"
Copy-Item -Path $LogFile -Destination $Des
}
#optional scriptblock to clean up
$SB2 =
{
Remove-Item -Path $TempDes -force
}
#Run the copy file scriptblock
Invoke-Command -Session $sess -ScriptBlock $SB
#Copy file
Copy-Item -FromSession $sess $TempDes "D:\logs\tomcat\" -Force #"
#Run clean up scriptblock
Invoke-Command -Session $sess -ScriptBlock $SB2
Have you considered using a PSDrive to map the remote location and then copy the file to or from that drive?
The New-PSDrive cmdlet creates temporary and persistent drives that
are mapped to or associated with a location in a data store, such as a
network drive, a directory on the local computer, or a registry key,
and persistent Windows mapped network drives that are associated with
a file system location on a remote computer.
Example using your code:
# Change the ServerNameToCopyTo below
New-PSDrive -Name "Remote" -PSProvider "FileSystem" -Root "\\ServerNameToCopyTo\log\tomcat\"
$LogFile = "D:\log\tomcat\access.20180227.log"
Copy-Item $LogFile "Remote:\" -Force
I'm using the following script to run test.reg on multiple remote systems:
$computers = Get-Content computers.txt
Invoke-Command -ComputerName $computers -ScriptBlock {
regedit /i /s "\\SERVER\C$\RegistryFiles\test.reg"
}
The script doesn't error, but the registry entry doesn't import on any of the systems.
I know test.reg file is a valid registry file because I copied it over, ran it manually, and the registry key imports. I also made sure PowerShell Remoting is enabled on the remote computers.
Any ideas why the registry key isn't importing?
I found the best way not to mess with issues related to server authentication and cut down on complexity just to pass Reg file as parameter to function.
$regFile = #"
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters]
"MaxUserPort"=dword:00005000
"TcpTimedWaitDelay"=dword:0000001e
"#
Invoke-Command -ComputerName computerName -ScriptBlock {param($regFile) $regFile | out-file $env:temp\a.reg;
reg.exe import $env:temp\a.reg } -ArgumentList $regFile
I posted on some PowerShell forums and finally got this working.
I had to 1) move the $newfile variable inside the loop and 2) comment out the $ in the path stored in the $newfile variable.
For reference, the final script looks like this if anyone wants to use it:
$servers = Get-Content servers.txt
$HostedRegFile = "C:\Scripts\RegistryFiles\test.reg"
foreach ($server in $servers)
{
$newfile = "\\$server\c`$\Downloads\RegistryFiles\test.reg"
New-Item -ErrorAction SilentlyContinue -ItemType directory -Path \\$server\C$\Downloads\RegistryFiles
Copy-Item $HostedRegFile -Destination $newfile
Invoke-Command -ComputerName $server -ScriptBlock {
Start-Process -filepath "C:\windows\regedit.exe" -argumentlist "/s C:\Downloads\RegistryFiles\test.reg"
}
}