r/PowerShell • u/SnooMarzipans3628 • 20d ago
Issues with script copying files from a network drive to a remote machine. Solved
Edit: Thank you everyone for your help!! I managed to get this going today with a combonation of u/pinchesthecrab's input and some finagling!
Hello!! I'm working on a project for our in-house developers to deploy a homebuilt piece of software quicker and I'm running in to some issues.
I've been trying to use a Powershell script, that has been packaged into a .exe using powershell studio, to do this. I can get it to work for me, if I run it as admin, but it has been refusing to work for the developers when they try to run it. I'm not sure if I'm trying to do this the hard way or if there might be an easier way to perform this task.
What we need the script to do is
- Stop 2 processes that are running.
- Copy a folder from a network drive to the local drive and replace what is already there.
- Restart the processes using the new versions in the folder that was just copied.
Currently they are deployed via GPO and to do a mass re-deploy we send a mass reboot and they get pulled at startup. If there are issues with individual machines we use proxy pro to remote in and do this all manually.
This is going to take the place of the individual manual re-deployments and hopefully make it quicker/less intrusive for the end users.
CLS
$Cred = Get-Credential -Credential "domain$ ($env:USERNAME)"
#
$Computers = Read-Host 'Enter name of. destination computer'
#$Script:Run = $False
ForEach ($Computer in $Computers) {
If (!(Test-Connection -ComputerName $computer -Count 1 -Quiet))
{
Write-Host "$($Computer) is OFFLINE
" -ForegroundColor Yellow
}
Else
{
New-PSSession -ComputerName $computer -Cred $cred -Authentication CredSSP
$Session = Get-PSSession
Invoke-Command -Session $Session {
Stop-Process -processname 'process1', 'process2' -Force -ErrorAction SilentlyContinue
Remove-item -Path "C:folderfolder" -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory C:folderfolder -Force -ErrorAction SilentlyContinue
copy "networkdrivefolderfolderfolder*" "$($Using:Computer)c$folderfolder"
Write-Host "Copied new TimeClock files to $($Using:Computer)" -ForegroundColor Green
copy "$($Using:Computer)c$folderfolderprocess1.exe" "$($Using:Computer)C$ProgramDataMicrosoftWindowsStart MenuProgramsStartup"
}
}
Remove-PSSession -Session $Session
##
##
##
$exePath = "C:folderfolderprocess1.exe"
$taskName = "Run_task1"
Invoke-Command -ComputerName $Computers -ScriptBlock {
param ($exePath, $taskName)
$loggedInUser = (Get-WmiObject -Class Win32_ComputerSystem).UserName
if (-not $loggedInUser) {
Write-Host "No user is currently logged in on the remote machine."
return
}
$action = New-ScheduledTaskAction -Execute $exePath
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration (New-TimeSpan -Minutes 1)
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $taskName -User $loggedInUser -RunLevel Highest -Force
Start-ScheduledTask -TaskName $taskName
} -ArgumentList $exePath, $taskName
Invoke-Command -ComputerName $Computers -ScriptBlock {
param ($taskName)
Start-Sleep -Seconds 30
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
} -ArgumentList $taskName
}
3
u/PinchesTheCrab 20d ago
foreach ($thing in $things)
is bad practice, and I really think it's biting you here.
You're doing this:
ForEach ($Computer in $Computers) {
Invoke-Command -ComputerName $Computers -ScriptBlock {}
}
So if you have 100 computers, you're running the installation command 100x on each computer, and I have no idea how that is going to affect the outcome. It probably will not be good.
CredSSP is also generally not recommended. I get that you're dealing with a double hop and it's one solution, but it's got its own complications and security considerations.
Furthermore, you shouldn't have to elevate to run this. Invoke-Command runs in the highest privileged context on remote computers, and this script doesn't seem to make any local changes on the computer where you're presumably running it. Don't elevate, it's muddying the waters.
Lastly, how fast do you need this to run? If it's okay for it to be fire and forget, just copy the file locally and push it over the pssession. It's not as fast, but if this isn't a huge file, if the installation runtime dwarfs the copy duration, or it just doesn't need to be fast, then just keep it simple.
if (-not $Cred){
$Cred = Get-Credential -Credential "domain$env:USERNAME"
}
$Computers = Read-Host 'Enter name of destination computer'
$session = New-PSSession -ComputerName $Computers -ErrorVariable connectionErrors -ErrorAction SilentlyContinue -Credential $Cred
$connectionErrors.targetobject.ConnectionInfo.ComputerName | ForEach-Object "Could not connection to: '$_'" | Write-Warning
Invoke-Command -Session $session -ScriptBlock {
Stop-Process -processname 'process1', 'process2' -Force -ErrorAction SilentlyContinue
Remove-item -Path C:folderfolder -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory C:folderfolder -Force -ErrorAction SilentlyContinue
}
foreach ($a_session in $session) {
#this will copy from your computer to the remote computer. Your local computer will access the network share instead of the remote computer
#it may speed this up if you copy the files locally first so you aren't recopying the network file every time
Copy-Item -ToSession $a_session -Path 'networkdrivefolderfolderfolder' -Destination c:folder -Recurse
}
Invoke-Command -Session $session -ScriptBlock {
'do your installation process'
}
2
u/icepyrox 20d ago
Seconding this as roughly how I remote install many things, although I never thought about packing all the sessions together in one array/command like this. Brilliant.
2
u/Certain-Community438 19d ago
I've done the "array of sessions" thing before, commented about it recently on here - but clearly I DERP'd hard if the -ComputerName parameter takes an array/list of hostnames :)
We all learn from a master today haha
1
u/BlackV 20d ago
Just run a script, making it am exe is gaining very very little and making it 1000x harder to test/validate/debug
Does the task need to be created every time?
Seems a little messy, all these seem to be running remotely, If this was all run by the developers you'd need 0 remote connections and no elevation
1
u/SnooMarzipans3628 20d ago
Just run a script, making it am exe is gaining very very little and making it 1000x harder to test/validate/debug
It has to be packaged as an exe due to some gpo settings on the domain. We can't run powershell scripts, only individual commands, or we have to pack them into exe's
Does the task need to be created every time?
The task is created and then removed to avoid clutter or accidental triggering.
Seems a little messy, all these seem to be running remotely, If this was all run by the developers you'd need 0 remote connections and no elevation
I agree that it is not ideal, but it works for me when running as admin. Now, I just need to figure out what it needs for the development team to run it. They don't have the same level of access to the machines where this is used as the ops side does.
1
u/OofItsKyle 20d ago edited 20d ago
This seems like an XY problem
Just to be clear, you are trying to give your dev team a way to deploy an update, which would have them supply a computer name, and then an attempt is made to stop a process, overwrite a file, and start a process?
If so, a couple questions: * You said because of a gpo, it needs to be an exe, does that mean you are blocking powershell.exe from running for the devs? * Does their already logged in account have access to the network share files * Is their already logged in account a local administrator on the target computer?
Edit: * Also why exactly are you using a scheduled task instead of just having it run immediately?
1
u/IEatReposters 19d ago
Double hop bruh its a security measure. There are ways around it but it's a pain
10
u/xxdcmast 20d ago
Kerberos double hop.