How do I upload files to remote servers using scripts - powershell

Batch: I can upload using xcopy but I would like to loop/recurse by using next server name from servers.txt
Powershell: Can't use copy-item because can't use -Credential. Use start-job and have error scriptblock "specify a parameters of type 'system.management.automation.scriptblock' and try again.```
what I have tried is in the summary and code provided.
PS1:
Read-Host "Er Password" -AsSecureString | ConvertFrom-SecureString | Out- File c:\temp\PSCred.txt
$Pass = cat PSCred.txt | ConvertTo-SecureString
$User = Read-Host "ER userID"
$computers = gc "C:\temp\servers.txt"
$source = "C:\temp\UPowercli.exe"
$destination = "C$\temp\"
foreach ($computer in $computers) {
$sb = [scriptblock]::create("Copy-Item $source -Destination \\$computer\$destination -Recurse")
start-job -scriptblock -Credential $User $Pass $sb
}
BAT:
C:\temp>net use \\server.domain.com /user:%user% %password%
The command completed successfully.
C:\temp>xcopy /y "c:\temp\uninstallpowercli.bat" "\\server.domain.com\c$\temp"

Related

PowerShell script to list files from sftp server folder

I am trying to get list of files from an SFTP folder using the following PowerShell script:
$files = Get-SftpChildItem -Host mysftpserver -Port 22 -Username myusername -Password mypassword -RemoteLocation "/MySFTPFolder/outbound/"
ForEach ($f in $files)
{
"test" | Out-File $ConfigFile -Append
}
For some reason I am not able to read the 2 files that are in the remote outbound folder. Is there something I am missing?
You may be running an old version of the Posh-SSH module, since your syntax looks very different than mine, and the fact that you don't have help files installed. You should install the latest version with:
Find-Module Posh-SSH | Install-Module
Then you can create a SFTP session, and use that session to list the child items as you desire:
$userName = 'MyUserName'
$secStringPassword = 'MyPassword' | ConvertTo-SecureString -AsPlainText -Force
$Creds = [pscredential]$credObject = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword)
$session = New-SFTPSession -computername mysftpserver -Credential $Creds
$files= Get-SFTPChildItem -SFTPSession $session -Path "/MySFTPFolder/outbound/"
ForEach ($f in $files)
{
"test" | Out-File $ConfigFile -Append
}

How to pass variable in Scriipt Block for use with Invoke-Command that will call an executable that takes the variable as switch param

I am attempting to create a generic script that will process registry files on a list of remote servers. The script will take the input of the path/filename to process and a list of servers to process it on. Copies the .reg file to the remote server and then attempts to process the .reg file on the remote server. In order to make it generic for use with any .reg file I want to pass the path\filename to process in a variable in the script block. I have seen examples of passing named variables and positional parameters but that doesn't seem to meet my requirements. I tried creating the script block contents as a Scriptblock type and calling it but it does not work. Most of the errors I have been getting are related to invalid parsing, ambiguous parameter, etc. I have seen a couple of working examples in which the .reg file path/filename is hard-coded but that defeats the purpose of what I am attempting to accomplish. I have tried the Invoke-Command with a session and with the -ComputerName variable in order to try the :using:" command with no success. Is there any way to pass a variable that is basically the command line values (switch params & filepath/name) for an executable within the scriptblock or am I going about this in the wrong manner? In code below I am crossing domains so having to open session for those servers in order to create directory if it doesn't exist.
while ($true)
{
$regFile = Read-Host -Prompt "Enter the path & name of registry file to be processed"
If(Test-Path -Path $regFile) { break }
Write-Host "You must enter valid path & filename of a registry file to process."
}
$servers = Get-Content D:\MLB\Scripts\servers.txt
$fileNm = [System.IO.Path]::GetFileName($regFile)
$pass = ConvertTo-SecureString "blahblah" -AsPlainText -Force
$Creds = new-object -typename System.Management.Automation.PSCredential( "domain\username", $pass)
foreach ($server in $servers)
{
$dirPath = ''
$newfile = '\\' + $server + '\d$\MLB\RegFiles\' + $fileNm
if($server.ToLower().Contains("web"))
{
$Session = New-PSSession -ComputerName $server -Credential $Creds
Invoke-Command -Session $Session -ScriptBlock { New-Item -ErrorAction SilentlyContinue -ItemType directory -Path D:\MLB\RegFiles }
$newfile = "d:\MLB\RegFiles\" + $fileNm
Copy-Item $regFile -Destination $newfile -ToSession $Session -Force
Remove-PSSession -Session $Session
}
else
{
$dirPath = "\\$server\d`$\MLB\RegFiles"
New-Item -ErrorAction SilentlyContinue -ItemType directory -Path $dirPath
$newfile = "\\$server\d`$\MLB\RegFiles\$fileNm"
Copy-Item $regFile -Destination $newfile -Force
}
Invoke-Command -ComputerName $server -Credential $Creds -ScriptBlock {
$args = "s/ $newfile"
Start-Process -filepath "C:\Windows\regedit.exe" -Argumentlist $args
}

MI_RESULT_FAILED on Copy-Item in PowerShell Script

I am running PowerShell on CentOS 7.x. I converted working individual commands when running within PowerShell via pwsh to a PowerShell script and then it no longer works. Can someone please shed me some light on what I did wrong?
Here's the working individual commands when running within PowerShell via pwsh.
PS /home/user1/Downloads> $userPw = ConvertTo-SecureString -String "user1password" -AsPlainText -Force
PS /home/user1/Downloads> cd
PS /home/user1> $userCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "user1win", $userPw
PS /home/user1> $s = New-PSSession -computerName 192.168.20.143 -credential $userCredential -Authentication Negotiate
PS /home/user1> Copy-Item -Path /home/user1/Downloads/gssntlmssp-0.7.0-1.el7.x86_64.rpm -Destination "C:\users\user1win\Desktop" -ToSession $s
PS /home/user1> exit
Here's the script when I converted to a PowerShell script so I can pass arguments into it. remote-copy.ps
$remoteHost = $args[0]
$username = $args[1]
$pwp = $args[2]
$source = $args[3]
$destination = $args[4]
Write-Host "Remote Host: '$remoteHost'"
Write-Host "Username: '$username'"
Write-Host "Password: '$pwp'"
Write-Host "Source: '$source'"
Write-Host "Destination: '$destination'"
$pw = ConvertTo-SecureString -String $pwp -AsPlainText -Force
$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $pw
$s = New-PSSession -computerName $remoteHost -credential $cred -Authentication Negotiate
Copy-Item -Path $source -Destination $destination -ToSession $s
When I run the script, I got the following error.
[user1#rhel7-tm PowerShell]$ pwsh -File ./remote_copy.ps 192.168.20.143 user1win user1password /home/user1/Downloads/vte-0.28.2-10.el7.x86_64.rpm "C:\\users\user1win\Desktop"
Remote Host: '192.168.20.143'
Username: 'user1'
Password: 'user1password'
Source: '/home/user1/Downloads/vte-0.28.2-10.el7.x86_64.rpm'
Destination: 'C:\users\user1win\Desktop'
Copy-Item:
Line |
19 |
Copy-Item -Path "$source" -Destination "$destination" -ToSession $s |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
Starting a command on the remote server failed with the following error message : MI_RESULT_FAILED For more information, see the about_Remote_Troubleshooting Help topic.
Copy-Item: Line |
19 |
Copy-Item -Path "$source" -Destination "$destination" -ToSession $s |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
Failed to copy file /home/user1/Downloads/vte-0.28.2-10.el7.x86_64.rpm to remote target destination.
I would be greatly appreciate if someone can point me to where I did wrong. Thanks!
It's a false alarm. The script does work. The issue is by default the MaxEnvelopeSizekb in winrm/config is only 500kb. I need to set to a bigger value if I want to send a bigger file. To set MaxEnvelopSizekb to 500mb, you need to open PowerShell on Windows as Administrator and run the following command.
PS C:\WINDOWS\system32> Set-WSManInstance -ResourceUri winrm/config -ValueSet #{MaxEnvelopeSizekb = "500000"}

I'm trying to remote into a server, run a script that resides on that server and capture the information displayed & store in a local file

##this code starts job but never exits or get any output###
clear
$test = 1
$Username = Read-host "Username (Example:Hosting.com\Your Username)"
""
$Pass = Read-Host -assecurestring "Password"
$Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass))
$Servers = Get-Content "c:\temp\new\Servers.txt"
foreach ($Server in $Servers)
{
$files= "c:\temp\new\new.ps1"
foreach ($file in $files)
{
xcopy $file \\$Server\C$ /Y
}
}
$CSVContent=#()
$sb = {c:\temp\new\PsExec.exe -h "\\$Server" /accepteula -u $Username -p $password -d cmd.exe /c "echo . | Powershell.exe -executionpolicy bypass -file c:\new.ps1 " > "$Test.txt"}
foreach ($Server in $Servers)
{
start-job -scriptblock $sb -ArgumentList $server
$test++
}
get-job | wait-job | receive-job
Here's something I just wrote up that will do what you want it to do and print all output to a file on the local PC (where you are running the script from)
$execDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
$Servers = Get-Content "c:\temp\servers.txt"
foreach ($Server in $Servers)
{
#echo $Server
copy-item "C:\temp\new\new.ps1" \\$server\c$\temp\
& "$execdir\psexec.exe" \\$server powershell.exe -noprofile -executionpolicy Bypass "C:\data\new.ps1" >> "C:\temp\logs.txt"
}
If the script says it cant run powershell.exe just add the full path to where the exe is locate
I'm not sure you will be able to get this working with jobs, unless you are using powershell v4 and use foreach -Parallel cmdlett
http://technet.microsoft.com/en-us/library/jj713711.aspx

Using Remove-Item with Credentials

I am attempting to use the Remove-Item cmdlet as part of an automation for a system. The files are stored on a server that requires elevated rights to perform the file deletion. I have access to a domain admin account that I use for such automation scripts.
The code below will build the PSCredential object:
$password = New-Object System.Security.SecureString
"passwordhere".ToCharArray() | ForEach-Object { $password.AppendChar($_) }
$cred = New-Object System.Management.Automation.PSCredential("domain\username",$password)
$cred
I am passing this object to the following action:
Remove-Item -LiteralPath $path -Force -Credential $cred
Any ideas?
It's not clear to me if the files are local (you're running the script on the server) or remote (on another machine). If local try running the command using a background job and pass in the credentials to Start-Job:
$job = Start-Job { Remove-Item -LiteralPath $path -force } -cred $cred
Wait-Job $job
Receive-Job $job
If they're remote, try using remoting:
Invoke-Command -computername servername `
-scriptblock { Remove-Item -LiteralPath $path -force } `
-Cred $cred
Note: This requires that you execute Enable-PSRemoting on the remote machine.
In general, putting raw passwords in your script isn't a great idea. You can store the password in an encrypted manner using DPAPI and later, only that user account can decrypt the password e.g.:
# Stick password into DPAPI storage once - accessible only by current user
Add-Type -assembly System.Security
$passwordBytes = [System.Text.Encoding]::Unicode.GetBytes("Open Sesame")
$entropy = [byte[]](1,2,3,4,5)
$encrytpedData = [System.Security.Cryptography.ProtectedData]::Protect( `
$passwordBytes, $entropy, 'CurrentUser')
$encrytpedData | Set-Content -enc byte .\password.bin
# Retrieve and decrypted password
$encrytpedData = Get-Content -enc byte .\password.bin
$unencrytpedData = [System.Security.Cryptography.ProtectedData]::Unprotect( `
$encrytpedData, $entropy, 'CurrentUser')
$password = [System.Text.Encoding]::Unicode.GetString($unencrytpedData)
$password
Remove-Item can fail due to authorisation. Alternatively, either find the reference for each file and hit it with a .Delete() or move all of the files to the recycle bin.
foreach ($svr in $computers)
{
Invoke-Command -ComputerName $svr {
$folderitems = Get-ChildItem $cachefolder -Recurse
# Method 1: .Delete
foreach ($cachefolderitem in $cachefolderitems)
    {
     if ($cachefolderitem -like "*.ini")
        {
$cachefolderitem.Delete()
        }
}
# Method 2: Move all matching files to the recycle bin
Move-Item "$cachefolder\*.ini" 'C:\$Recycle.Bin' -Force
}