Copy-Item throws AccessDenied exception - powershell

I am trying to copy files from a remote server to my base machine using powershell. This throws an 'Access Denied' exception even though the drives get mapped:
New-PSDrive -Name source -PSProvider FileSystem -Root "\\SERVERNAME1\D$\Temp\Folder" ;
New-PSDrive -Name target -PSProvider FileSystem -Root $destinationRemotePath ;
Copy-Item -Path source:\$($file).zip -Destination target: -Verbose -ErrorAction Stop -Force ;
Approach 2
I am mapping the source drive and using PsSession for target drive but I get
Cannot find drive. A drive with the name 'source' does not exist.
+ CategoryInfo : ObjectNotFound: (source:String) [Copy-Item], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
Following is the code being used:
$Username = "UserName";
$Password = ConvertTo-SecureString "Password" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username, $Password)
$session = new-pssession -computername 'TargetServerName' -credential $cred
New-PSDrive -Name source -PSProvider FileSystem -Root "\\SERVERNAME1\D$\Temp\Folder" ;
Invoke-Command -Session $session -ScriptBlock { Copy-Item -Path $($args[0]) -Destination $($args[1]) -Verbose -ErrorAction Stop } -ArgumentList source:\$($file).zip,'D:\Folder' ;

There are some issues on that second example:
The PSSession has a different scode, it does not know about your PSDrive.
PSSessions do not support authentication to network location like you might be used to from RDP-Sessions. See CredSSP or ' PSSession double hop'
Approach 1 looks like you have no access to that share you want to use. You can specify credentials via -Credential parameter at New-PSDrive. Can you Get-Childitem on Source: and Target:?

Related

How do I use Powershell on my computer to use another computer to copy files from a third computer to a fourth computer?

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?

PowerShell Issue regarding entering a PS Session and setting permissions

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
}

How to create registry on multiple remote machine

I'm creating a registry key on remote machine with below code:
$basePath="C:\Users\<User>\Desktop\Script\"
$remoteMachineName = $basePath + "server.txt"
$arrServer=(Get-Content $remoteMachineName)
$remoteUserPassword = Get-Content "C:\Users\<UserName>\Desktop\Script\pass.txt"
ConvertTo-SecureString -AsPlainText -Force -String $password
$credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "UserName"
Enter-PSSession -ComputerName $server -Credential $credentials
New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType "String" -Path "HKLM:\SOFTWARE\Usertest"
But it creates registry key on my local machine however I want it on remote machine giving below error :
New-ItemProperty : The property already exists.
At C:\Users\<User>\Desktop\Script\Untitled4.ps1:14 char:1
+ New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceExists: (HKLM:\SOFTWARE\Usertest\:String) [New-ItemProperty], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.NewItemPropertyCommand
But when I run command Enter-PSSession and New-ItemProperty separately it works but I want to run both the commands simultaneously.
Please Help me to create registry Key on remote machine.
Just use the Invoke-Command cmdlet:
# ...
Invoke-Command -cn $server -cred $credentials {
New-ItemProperty -Name "myReg" -Value "ABC" -PropertyType "String" -Path "HKLM:\SOFTWARE\Usertest" -Force
}

Using -Credential with Copy-Item failure

I am trying to copy a file to a UNC filename where my user has permission, but no traditional drive letter mapping. PSVersion 5.0.10586.11
# Get and store the password in an encrypted file. Do this once only.
# (Get-Credential).Password | ConvertFrom-SecureString | Out-File .\my_secret.txt"
$user = "me"
$file = ".\my_secret.txt"
$cred = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList $user, (Get-Content $file | ConvertTo-SecureString)
Copy-Item -Credential $cred .\list.txt "\\zeplin.nowhere.org\data\docs\log"
Running the script seems to suggest that Copy-Item does not support -Credential. I would rather not create a new drive letter mapping with New-PSDrive unless I must. Using Get-Help Copy-Item shows that it supports the -Credentials parameter. The following error message is returned.
The FileSystem provider supports credentials only on the New-PSDrive cmdlet. Perform the operation again without specifying
credentials.
PS C:\Users\me> .\t.ps1
At C:\Users\me\t.ps1:8 char:1
+ Copy-Item -Credential $cred .\list.txt "\\zeplin.nowhere.org\data\docs ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotImplemented: (:) [], PSNotSupportedException
+ FullyQualifiedErrorId : NotSupported
Copy-Item has a Credential parameter for PS providers that support it. The FileSystem provider, as indicated, does not. You'll have to use New-psdrive.

Powershell OnlyInJobError

Weird problem I saw today and I don't understand.
Is there a difference beetween running a script manually in the ISE or Pshell, and as a job?
If I run it manually the code doesn't throw an error - runs smoothly:
Get-ChildItem "\\SERVER\S$\ROOT\DIR" -Recurse | Where {$_.creationtime -lt (Get-Date).AddDays(-35)} | Remove-Item -Force -Include *.conf
But if I run it via Job and let the it export the $error to a txtfile this happens:
Are the rights of my running machine different to the rights of the scheduled job?
Get-ChildItem : Zugriff verweigert
In Zeile:81 Zeichen:1
+ Get-ChildItem "\\SERVER\S$\ROOT\DIR" -Recurse | Where
{$_.creati ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-ChildItem], UnauthorizedA
ccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.Pow
erShell.Commands.GetChildItemCommand
Zugriff verweigert = Access denied
Oh, totally forgot to tell about my windows rights.
Normally the Server I am connecting to is blocked for everybody - except for login with credentials ofc. But somehow my manual powershell script is able to delete and create files?
In "job-mode" it loses it's abilities.
Edit:
Same for the Test-Path commandlet. Manually it shows me true or false. Via job it throws an error.
EDIT - SAME PROBLEM COMPLETELY DIFFERENT Commandlets:
$username = "Administrator"
$password = cat C:\securestring.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
New-PSDrive -Name Z -PSProvider FileSystem -Root \\Server\ROOT -Credential $cred -Persist
test-path 'Z:'
Remove-PSDrive -Name Z -PSProvider FileSystem
This works!
This does not:
$jobname = "Test5"
$JobTrigger = New-JobTrigger -Daily -At "00:18 PM"
$MyOptions = New-ScheduledJobOption -ContinueIfGoingOnBattery -HideInTaskScheduler -RunElevated
Register-ScheduledJob -name "$jobname" -scriptblock {
$username = "Administrator"
$password = cat C:\securestring.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
New-PSDrive -Name Z -PSProvider FileSystem -Root \\Server\ROOT -Credential $cred -Persist
test-path 'Z:'
Remove-PSDrive -Name Z -PSProvider FileSystem
} -trigger $JobTrigger –ScheduledJobOption $MyOptions
You probably have the job running under the SYSTEM account. Use the -Credential parameter to provide your account credentials (whatever account you're logged in with when you successfully run the command interactively).
BTW, Register-ScheduledJob uses the Task Scheduler. You can check the properties of the job in Task Scheduler to see what account it's configured to run as.
Well, it is not exactly an answere to my original question, but I was able to work around my problem by using the invoke-command and test-path from there and giving argument via the -arg.
Invoke-Command -ComputerName $FTPADRESS -ArgumentList $DIRECTORY -ScriptBlock {param ($DIR)
$check = Test-Path -Path "\\SERVER\ROOT\$DIR"
if ($check -ne $true) {New-Item -ItemType directory -Path "\\SERVER\ROOT\$DIR"}
}
Same works with the get-childitem.