Invoke-Command in a foreach

Hello friends,

I’m still a Powershell rookie and to step up my scripting I’m working on a script that check the version of all servers in the list, copy a patch file to the server and then execute wusa.exe to install the patch. I do have access rights on the server and share and I’m able to to copy the file if I just run it as a oneliner.

If I’m running the script I get the following error:

Access is denied
+ CategoryInfo : PermissionDenied: (\server\share.…4499164-x64.msu:String) [Copy-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand
+ PSComputerName : WEB

$Serverlist = "WEB1", "WEB2"

foreach($Server in $Serverlist){

$RemoteServerIntallPath = "\\$Server\C$\Temp\Patches"

IF (Test-Connection -ComputerName $Server -Count 1 -Quiet){
Write-Host "Ping $Server"

IF(!(Get-HotFix -ComputerName $Server -Id "KB4499149" -InformationAction SilentlyContinue)){
Write-Host "Hotfix needed of $server!"

IF(!(Test-Path $RemoteServerIntallPath)){
New-Item -Path $RemoteServerIntallPath -ItemType Directory | Out-Null
Write-Host "Directory created: $RemoteServerIntallPath"
Write-Host "Folder exists on $Server!"

Invoke-Command -ComputerName $Server -ScriptBlock {
$RemoteServerIntallPath = "\\$env:COMPUTERNAME\C$\Temp\Patches"
$WinSRV2008R2 = "\\Server\share\windows6.1-kb4499164-x64.msu"
$WinSRV2008SP2 = "\\Server\share\windows6.0-kb4499149-x64.msu"
$OSVersion = Get-CimInstance -ClassName Win32_OperatingSystem -Property Version
#$Cred = Get-Credential

IF($OSVersion.Version -like "6.1.*"){
Copy-Item -Path $WinSRV2008R2 -Destination $RemoteServerIntallPath -Verbose #-Credential $Cred
#Copy-Item -Path "\\Server\share\windows6.1-kb4499164-x64.msu" -Destination $RemoteServerIntallPath
Write-Host "Kopied file to $env:COMPUTERNAME"
Start-Process 'wusa.exe' -ArgumentList 'C:\Temp\patches\kb4103712.msu', '/quiet', '/norestart'

}elseif($OSVersion.Version -like "6.0.*"){
        Write-Host "$Server is a Windows Server 2008 SP2"
Write-Host "$Server is not a Windows Server 2008 SP2 or 2008 R2"


You may have permissions to the server and the share, but unless the PowerShell session you are running, is running as a account on the targets that is in the local administrators group, your command will fail.

With the exception of only a handful of cmdlets, you must be in the target host local admin group for PSRemoting to work.

Also, why not just copy to installer to the RunOnce location, and restart the system, vs trying to run this installer remotely?

Hi Postanote,

Thanks for your reply and sorry for the late reply.

I found another soloution with PsExec.

$RootHotfixPath = '\\Server\Rollup\2008 R2\'

$Hotfixes = @('windows6.1-kb4499164-x64.msu')
$Servers = "WEB"

foreach ($Server in $Servers)
Write-Host "Processing $Server..."

$needsReboot = $False
$remotePath = "\\$Server\c$\Temp\Patches\"

if( ! (Test-Connection $Server -Count 1 -Quiet)) 
Write-Warning "$Server is not accessible"

if(!(Test-Path $remotePath))
New-Item -ItemType Directory -Force -Path $remotePath | Out-Null

foreach ($Hotfix in $Hotfixes)
Write-Host "`thotfix: $Hotfix"
$HotfixPath = "$RootHotfixPath$Hotfix"

Copy-Item $Hotfixpath $remotePath
# Run command as SYSTEM via PsExec (-s switch)
& "C:\Program Files (x86)\SysinternalsSuite\PsExec" -s \\$Server wusa C:\Temp\Patches\$Hotfix /quiet /norestart
write-host "& C:\Windows\PsExec -s \\$Server wusa C:\Temp\Patches\$Hotfix /quiet /norestart"
if ($LastExitCode -eq 3010) {
$needsReboot = $true

# Delete local copy of update packages
Remove-Item $remotePath -Force -Recurse

Write-Host "Restarting $Server..."
Restart-Computer -ComputerName $Server -Force -Confirm