Problem: Robocopy not launching as another user in Start-Process
The script works fine when running on an account that has the permissions for both file locations but it just doesnt seem to be accepting the -credential param.
Unsure if my formatting is incorrect or if I am doing something wrong.
# Create Password for credential
$passw = convertto-securestring "Password" -asplaintext –force
# Assembles password into a credential
$creds = new-object -typename System.Management.Automation.PSCredential -argumentlist "DOMAIN\Username", $passw
# Select a source / destination path, can contain spaces
$Source = '\\Source\E$\Location'
$Destination = '\\Destination\Location Here'
# formats the arguments to allow the credentials to be wrapped into the command
$RoboArgs = "`"$($Source)`" `"$($Destination)`"" + " /e /Copy:DAT"
# Started Robocopy with arguments and credentials
Start-Process -credential $creds Robocopy.exe -ArgumentList $RoboArgs -Wait
Robocopy will use the standard windows authentication mechanism.
So you probably need to connect to the servers using the appropriate credentials before you issue the robocopy command.
You can use net use to do this.
net use X: '\\Source\E$\Location' /user:MYDOMAIN\USER THEPASSWORD
net use Y: '\\Destination\Location Here' /user:MYDOMAIN\USER THEPASSWORD
net use X: /d
net use Y: /d
and then start your ROBOCOPY
S.Spieker's answer will work, but if you want to use PowerShell built in command and pass the credentials as a pscredential object you could use New-PSDrive to mount the drives:
$passw = convertto-securestring "Password" -asplaintext –force
$creds = new-object -typename System.Management.Automation.PSCredential -argumentlist "DOMAIN\Username", $passw
$SourceFolder = '\\Source\E$\Location'
$DestinationFolder = '\\Destination\Location Here'
New-PSDrive -Name MountedSource -PSProvider FileSystem -Root $SourceFolder -Credential $creds
New-PSDrive -Name MountedDestination -PSProvider FileSystem -Root $DestinationFolder -Credentials $creds
Robocopy.exe \\MountedSource \\MountedDestination /e /Copy:DAT"
Remove-PSDrive -Name MountedSource
Remove-PSDrive -Name MountedDestination
* I might have the Robocopy wrong, it's been years since I used it, but the mounting drives is correct.
Related
This is the first time posting on SO (and really on any public platform), so I apologize if this question was already answered or if the question isn't structured appropriately.
I am brand new to creating PowerShell Scripts and I'm hoping someone can assist me on my new scripting adventure!
The script I am trying to create is to gather user input on OS user credentials, the OS user password, and the remote server's IP Address\FQDN\Hostname. From there I want to create a ps1 file that a scheduled task will point to, which will copy a particular folder from one server to a remote server on a daily basis (replacing the remote servers folder). I am getting caught up on properly adding the needed lines using the New-Item and Add-Content cmdlets
Here is my script I created so far:
#Clear the Screen
Clear-Host
#Create Variable for OS User Account
$User = read-host "What is the OS User that has permissions to the remote web server?"
#Clear the Screen
Clear-Host
#Password for OS User Account
$Password = Read-Host "What is the password of the OS account that has permissions to the remote web server?"
#Clear the Screen
Clear-Host
#Convert Password String
$PWord = ConvertTo-SecureString -String $Password -AsPlainText -Force
#Combine User Name and Password into One Entity
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
#IP Address of Destination ICA Web Server
$DestServer = Read-Host "What is the IP address\FQDN\Hostname of the Destination Web Server"
#Create a PowerShell File that will be used for Task Scheduler
New-Item "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" -ItemType File -Force -Value "$PWord = ConvertTo-SecureString -String $Password -AsPlainText -Force"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" ""
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" ""
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "$Session = New-PSSession -ComputerName $DestServer -Credential $Credential"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "Copy-Item `"C:\Web\Web\Download`" -Destination `"C:\Web\Web\`" -ToSession $Session -Recurse -Force"
This is the results that I get in the ps1 that gets created (Used 'TestUser' for the OS user, 'PW' for the password, and '10.10.10.10' for the remote server):
System.Security.SecureString = ConvertTo-SecureString -String PW -AsPlainText -Force
System.Management.Automation.PSCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList TestUser, System.Security.SecureString
= New-PSSession -ComputerName 10.10.10.10 -Credential System.Management.Automation.PSCredential
Copy-Item "C:\Web\Web\Download" -Destination "C:\Web\Web\" -ToSession -Recurse -Force
On the first line, for some reason it displays 'System.Security.SecureString' rather than the $PWord variable.
The second line displays 'System.Management.Automation.PSCredential' & System.Security.SecureString rather than the $Credential & $PWord variables.
The third line does not display the $Session variable. It also displays 'System.Management.Automation.PSCredential' rather than the $Credential variable.
The fourth line does not display the $Session variable
So it looks like Powershell doesn't like me adding variables using the New-Item & Add-Content cmdlets.
Any input/suggestions is greatly appreciated!! Thank you!
UPDATE: Thank you, mklement0, for providing the missing piece to my puzzle!
Here is an updated working script based off the information provided by mklement0
#Clear the Screen
Clear-Host
#Create Variable for OS User Account
$User = read-host "What is the OS user account that has permissions to the remote web server?"
#Clear the Screen
Clear-Host
#Password for OS User Account
$Password = Read-Host "What is the password of the OS user account that has permissions to the remote web server?"
#Clear the Screen
Clear-Host
#Convert Password String
$PWord = ConvertTo-SecureString -String $Password -AsPlainText -Force
#Combine User Name and Password into One Entity
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
#IP Address of Destination ICA Web Server
$DestServer = Read-Host "What is the IP address, FQDN, or Hostname of the remote web server"
#Create a PowerShell File that will be used for Task Scheduler
New-Item "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" -ItemType File -Force -Value "`$OSUser = `"$User`""
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" ""
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "`$PWord = ConvertTo-SecureString -String `"$Password`" -AsPlainText -Force"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "`$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList `$OSUser, `$PWord"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" ""
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "`$Session = New-PSSession -ComputerName `"$DestServer`" -Credential `$Credential"
Add-Content "C:\Test\ScheduledTask\CopyPasteDownLoadFolder.ps1" "Copy-Item `"C:\Web\Web\Download`" -Destination `"C:\Web\Web\`" -ToSession `$Session -Recurse -Force"
$ characters that you want to retain as-is inside an expandable (double-quoted) string ("...") must be escaped as `$, otherwise they and what follows are subject to string interpolation; e.g.:
$foo = 'bar'
# Note the ` (backtick) before the first $, which escapes it.
# The second $foo, which is unescaped is expanded (interpolated).
"Variable `$foo contains $foo"
The above yields verbatim:
Variable $foo contains bar
I wanted to reach out and see if anyone has some tips on impersonation/runas cmds. I am working on a script that exports, then imports a .pfx certificate over to the users profile from the admin profile. Right now, I have everything working except for the import portion.
As seen below, I am showing only the import portion. $x and $y variables are defined earlier in the script by user input and that works okay.
Everything works up until the import-pfxcertificate cmdlet and scriptblock. Running that scriptblock as the other use is proving to be difficult. If anyone has any advice on how to structure that scriptblock cmd so that it will runas the user, that would be great!
I have an error log written into the script as well (not shown) Unfortunately, it is not picking up any errors because I believe it is pulling a local machine cert rather than the cert I specified - so no real error messages.
<#Cache credentials in IE and Import new or existing cert as client#>
function importcert
{
certpath = "C:\Temp\$x.pfx"
$password = $y | ConvertTo-SecureString -AsPlainText -Force
<#Enter your credentials#>
Credentials = Get-Credential -Credential corp\$x
<#Export to Secure XML#>
$Credentials | Export-Clixml -path 'C:\Temp\creds.xml'
<#Import credentials and run application using those credentials#>
Set-Location C:\
$creds = Import-Clixml -Path 'C:\Temp\creds.xml'
$ie = Start-Process -FilePath 'C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE' -Credential $creds
$ie
Start-Sleep -Seconds 30
<#Imports the certificate as the client#>
Start-Job -ScriptBlock { Import-PfxCertificate -FilePath $certpath -Exportable -CertStoreLocation Cert:\CurrentUser\My -Password $password } -Credential $creds
<#Search For Client Credential and if path is false, the credential file was removed successfully.#>
$clientXML = Test-Path -Path "C:\Temp\creds.xml"
Remove-Item -Path "C:\Temp\creds.xml"
if (-not ($clientXML))
{
Write-Output "Credential XML was removed"
}
}
importcert
It looks like all you're missing is some arguments for your Start-Job. I just tested this out locally and got it to install mycert.pfx for the other user TomServo:
<#Cache credentials in IE and Import new or existing cert as client#>
$Certpath = Get-Item "C:\Projects\Sandbox\mycert.pfx"
$Password = '{Password}' | ConvertTo-SecureString -AsPlainText -Force
<#Enter your credentials#>
$Credentials = Get-Credential -UserName TomServo
<#Export to Secure XML#>
$Credentials | Export-Clixml -path 'C:\Projects\Sandbox\creds.xml'
<#Import credentials and run application using those credentials#>
Set-Location C:\
$Creds = Import-Clixml -Path 'C:\Projects\Sandbox\creds.xml'
$Ie = Start-Process -FilePath 'C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE' -Credential $Creds
$Ie
Start-Sleep -Seconds 30
<#Imports the certificate as the client#>
Start-Job -ScriptBlock {
param($certpath, $Password)
Import-PfxCertificate -FilePath $Certpath -Exportable -CertStoreLocation Cert:\CurrentUser\My -Password $Password
} -Credential $Creds -ArgumentList $Certpath, $Password
<#Search For Client Credential and if path is false, the credential file was removed successfully.#>
$ClientXML = Test-Path -Path "C:\Projects\Sandbox\creds.xml"
Remove-Item -Path "C:\Projects\Sandbox\creds.xml"
if (-not ($ClientXML))
{
Write-Output "Credential XML was removed"
}
OK so below is my little script that I have come up with that should copy files from my local drive to a remote server using a local server admin user.
$User = "SERVER-NAME\MyUser"
$Password = "Password"
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("X:", "\\SERVER-NAME\c$\MyTestFolder\", $false, $User, $Password)
Copy-Item -Path "D:\Path\To\Copy\From" -Destination "X:\" -Recurse -Force -PassThru -Verbose
For some reason I am getting the following error, even though the server is reachable from my machine:
Exception calling "MapNetworkDrive" with "5" argument(s): "The network path was not found."
So it seems that the script is able to copy files only if the folder was actually shared over the network (Folder Properties -> Sharing -> Advanced Sharing). No actual remote access to a file system (which is kinda disappointing).
Here's the simplified version of the script I ended up with:
$User = "SERVER-NAME\AdminUser"
$Password = "Password"
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("x:", "\\SERVER-NAME\TestFolder", $false, $User, $Password)
Copy-Item -Path "D:\Path\To\Copy\From" -Destination "x:\" -Recurse -Force -PassThru
$net.RemoveNetworkDrive("x:", 0)
try to create drive with new-psdrive, like this:
$userCRED = "SERVER-NAME\MyUser"
$pass="Password"
$passCRED = ConvertTo-SecureString -String $pass -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $userCRED, $passCRED
$DestinationExport="\\SERVER-NAME\c$\MyTestFolder"
New-PSDrive -Name X -PSProvider filesystem -Root $DestinationExport -Credential $cred
Copy-Item -Path "D:\Path\To\Copy\From" -Destination "X:\" -Recurse -Force -PassThru -Verbose
Remove-PSDrive -Name X
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.
I am trying to create a new Win 2008 server local user and assign the user a different profile path. I don't want Windows to generate all the files under C:\Users\newUser, instead, I'd like to have it do that in D:\customDir\newUser. Does anyone know of a way to do this?
So far this is what I have:
$users= #("U1","U2","U3")
$computer = [ADSI]"WinNT://$env:COMPUTERNAME,computer"
$group = [ADSI]"WinNT://$env:COMPUTERNAME/MyCustomGroup,group"
$users | foreach {
$userName = $_
$userPath = "D:\customDir\$userName"
echo "Creating $userName..."
$user = $computer.Create("User",$userName)
$user.put("description","User $userName Description")
#$user.put("profilePath",$userPath) #This does not work, throws an error
#$user.put("homeDirDrive","D:") #This appears to be ignored when uncommented
$user.setpassword($userName)
$user.setInfo()
$group.add($user.Path)
#run cmd from user account to create profile files/folders
$spw = ConvertTo-SecureString $userName -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
}
The script successfully creates the users and adds them to the custom group, but all the files/folders end up in C:\Users\U*
To the OP,
Thanks for this piece, I was trying to figure out how to make this work for me:
run cmd from user account to create profile files/folders
$spw = ConvertTo-SecureString $userName -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
but I had to modify the last line to get it to work:
Start-Process cmd /c -Credential $cred -ErrorAction SilentlyContinue -LoadUserProfile
This works fine.
$loginName="ChrisMcCormack"
$newPass="123456ABCDEFG" # obviously generate a proper password...
$desc="average user"
$localHost=[ADSI]"WinNT://localhost"
$newUser=$localHost.Create("user",$loginName);
$newUser.setPassword($newPass);
$newUser.put("HomeDirectory","c:\users\$loginName");
$newUser.put("description",$desc);
$newUser.setInfo();
You can also use:
$spw = ConvertTo-SecureString $newPass -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $loginName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
to create the users directories without logging the user on.
Chris
Here is the way I use according to the underlaying COM component object model and the IADsUser interface.
$obj = [ADSI]"WinNT://$env:COMPUTERNAME"
$user1=$obj.create("user", "utilisateur1")
$user1.PasswordExpired=0
$user1.Invoke("setpassword","test.2012")
$user1.Invoke("put", "HomeDirectory", "c:\silogix")
$user1.Invoke("put", "Profile", "c:\docs")
$user1.Invoke("put", "LoginScript", "test.cmd")
$user1.CommitChanges()
Here is the result.
The only thing I can think of for you would be to change it at the registry level. Note that I'm not recommending you mess with the registry, but this does do what you want -
The default directory for a new profile is determined by the ProfilesDirectory in HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList, and by default is %SystemDrive%\Users, changing it to $userpath should do what you want -
$regpath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList"
$regname = "ProfilesDirectory"
set-itemproperty -path $regpath -name $regname -value $userpath
Hope that helps!