NET USE only works once in powershell - powershell

My requirement is to connect to a remote computer, copy files with the extension of .TRA to a different remote computer.
Now my difficulty arises in that the source machine aren't on the domain so I need to connect with alternate credentials.
My first sticking point is trying to use New-PSDrive. It doesn't appear to allow me to pass stored credentials. I have tried various versions of this:
$cred = Get-Credential
New-PSDrive -NAME Z: -PSprovider Filesystem -root \\Computer\Exchange -credentials $cred
and I get an error
The provider does not support the use of credentials. Perform the operation again without specifying credentials.
This appears to be a bug (see halr9000's comment here : Connecting to a network folder with username/password in Powershell)
My alternative was to use NET USE, which works fine but only once.
In the full script below I map to 8 different machines. The first of these works. After that any attempt to use NET USE (or New-Object WScript.NETWORK, mentioned as a work around on the Technet article linked above) fails. Or rather it doesn't fail.
Its creates a mapped drive, which I can see if I type NET USE, or if I look in explorer (and its browsable). But I cannot connect to that drive in Powershell. Its like it doesn't exist, Test-Path Z: returns False. Right up until I run NET USE Z: /D which successfully deletes the drive.
Can someone please help me with one or other of my issues please? Don't make me do this in DOS!
Full script :
$int = 0
$arrStagePC = "BOX42", "BOX43", "BOX44", "BOX45", "BOX46", "BOX47", "BOX48", "BOX49"
$arrData = "0848","5144","5292","5383","2158","2646","0061","2331"
Foreach($strComp in $arrStagePC)
{
$arr = $arrData[$int]
$comp = $strComp
net use z: \\$arr\Exchange /user:admin password
Copy-Item z:\*$date.tra \\$comp\Export$
net use z: /d
$int++
}
EDIT
Have a look at #Christians accepted answer below. I didn't actually need to Get-Content that folder, I just needed to copy data from the source so the bit of the script doing the business on there now looks like :
Foreach($strComp in $arrStagePC)
{
$arr = $arrData[$int]
$comp = $strComp
net use z: \\$arr\Exchange /user:admin password
Copy-Item FILESYSTEM::Z:\*.TRA \\$comp\Export$
net use z: /d
$int++
}

Using NET USE try access in this way:
Set-Location FILESYSTEM::Z:

Had same issue. Mended mine by adding
*New-PSDrive z FileSystem z:*
after the NET USE. Seems like NET USE /DELETE disturbs the PS housekeeping.

Try this, maybe:
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("Z:", "\\$arr\Exchange", $false, "admin", "password")

Related

Execute an Uninstall-Setup from server on remote computers via PowerShell

This is my first question here and I am also quite new on PowerShell, so I hope I am doing everything alright.
My problem is the following: I want to uninstall a programm on several computers, check if the registry-key is deleted and then install a new version of the programm.
The setup is located on a server within the same domain as the computers.
I want my Script to loop through the computers and execute the setup from the server for every computer. As I am quite new with PowerShell, I have no idea how to do this. I was thinking to maybe use Copy-Item, but I dont want to really move the setup, but simply execute it from the server to the computers? Any idea how to do this?
Best regards
You can try the following approach.
Note that the need to provide credentials explicitly is a workaround for the infamous double-hop problem.
# The list of computers on which to run the setup program.
$remoteComputers = 'computer1', 'computer2' # ...
# The full UNC path of the setup program.
$setupExePath = '\\server\somepath\setup.exe'
# Obtain credentials that can be used on the
# remote computers to access the share on which
# the setup program is located.
$creds = Get-Credential
# Run the setup program on all remote computers.
Invoke-Command -ComputerName $remoteComputers {
# WORKAROUND FOR THE DOUBLE-HOP PROBLEM:
# Map the target network share as a dummy PS drive using the passed-through
# credentials.
# You may - but needn't - use this drive; the mere fact of having established
# a drive with valid credentials makes the network location accessible in the
# session, even with direct use of UNC paths.
$null = New-PSDrive -Credential $using:cred dummy -Root (Split-Path -Parent $using:$setupExePath) -PSProvider FileSystem
# Invoke the setup program from the UNC share.
& $using:$setupExePath
# ... do other things
}

New-PSDrive drive mapping name

In my powershell script i am using New-PSDrive function to map remote server file path into my local computer as windows deployment operation proccess.
I plan to reuse this Powershell script in the future, so i dont want any conflict between drives because of naming. For example, if two deployment operations need to reach the script at the same time, then one of two will be deployed uncorrectly.
That's the question: Can i use timestamp or any other unique information as a drive mapping name? That way, i can be sure of avoiding name conflict.
Edit:
I have tried to create custom named new-psdrive mapping without persist parameter, but that way, powershell tries to reach the folder with relative path (under the current working directory)
Here is the code where i try to copy some files (backup):
$day = Get-Date -Format "yyyyMMdd"
$appsource = "\\$computername\D$\Applications"
New-PSDrive -Name J -PSProvider FileSystem -Root $appsource-Credential $cred -persist
Write-Host "Backup işlemi başladı."
robocopy "J:\App" "J:\backup\$day"
Edit 2:
You can not use a dynamic name as a persisted drive mapping name. If you are to reach cross domain computer, the best way is (but cost-effective way) to use Invoke-Command for running script on remote computer. 2 way (remote-local, local-remote) file-sharing permissions are need to be allowed. If you use Invoke-Command, you are conflict-free. Because the command uses dynamic session on the remote computer.
Per the documentation from Get-Help New-PSDrive -full, the name of the new drive is supplied as a string, so if you can build up the string from your preferred information (timestamp, etc.) before passing it to New-PSDrive, you can use it as a drive name. Note that you should avoid characters that will be problematical in pathnames, such as spaces and the reserved characters (e.g., \, :,/, the wildcard characters, etc.).
Since your edit shows that you're using ROBOCOPY, which runs "outside" PowerShell's code/memory space, you may not be able to use New-PSDrive to establish the mapping - I've had inconsistent results with this. Much more reliable is to establish the mapping with NET USE - in your case, NET USE J: $appsource will likely do the trick.
Since Windows-mapped drives have hard requirements on names (which is what is created when using the persist parameter) it may be better to use invoke-command and pass in a script block than mapping the drive at all.
$SB = {
$day = Get-Date -Format "yyyyMMdd"
Robocopy "D:\Test\App" "D:\Test\backup\$day"
}
Invoke-Command -ComputerName $CompName -Credential $cred -ScriptBlock $SB
This way it removes the need to worry about mapped drive collision

Powershell - Copying File to Remote Host and Executing Install exe using WMI

EDITED: Here is my code now. The install file does copy to the remote host. However, the WMI portion does not install the .exe file, and no errors are returned. Perhaps this is a syntax error with WMI? Is there a way to just run the installer silently with PsExec? Thanks again for all the help sorry for the confusion:
#declare params
param (
[string]$finalCountdownPath = "",
[string]$slashes = "\\",
[string]$pathOnRemoteHost = "c:\temp\",
[string]$targetJavaComputer = "",
[string]$compname = "",
[string]$tempPathTarget = "\C$\temp\"
)
# user enters target host/computer
$targetJavaComputer = Read-Host "Enter the name of the computer on which you wish to install Java:"
[string]$compname = $slashes + $targetJavaComputer
[string]$finalCountdownPath = $compname + $tempPathTarget
#[string]$tempPathTarget2 =
#[string]$finalCountdownPath2 = $compname + $
# say copy install media to remote host
echo "Copying install file and running installer silently please wait..."
# create temp dir if does not exist, if exist copy install media
# if does not exist create dir, copy dummy file, copy install media
# either case will execute install of .exe via WMII
#[string]$finalCountdownPath = $compname + $tempPathTarget;
if ((Test-Path -Path $finalCountdownPath) )
{
copy c:\hdatools\java\jre-7u60-windows-i586.exe $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
else {
New-Item -Path $finalCountdownPath -type directory -Force
copy c:\hdatools\dummy.txt $finalCountdownPath
copy "c:\hdatools\java\jre-7u60-windows-i586.exe" $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
I was trying to get $Job = Invoke-Command -Session $Session -Scriptblock $Script to allow me to copy files on a different server, because I needed to off load it from the server it was running from. I was using the PowerShell Copy-Item to do it. But the running PowerShell script waits until the file is done copying to return.
I want it to take as little resources as possible on the server that the powershell is running to spawn off the process on another server to copy the file. I tried to user various other schemes out there, but they didn't work or the way I needed them to work. (Seemed kind of kludgey or too complex to me.) Maybe some of them could have worked? But I found a solution that I like that works best for me, which is pretty easy. (Except for some of the back end configuration that may be needed if it is is not already setup.)
Background:
I am running a SQLServer Job which invokes Powershell to run a script which backups databases, copies backup files, and deletes older backup files, with parameters passed into it. Our server is configured to allow PowerShell to run and under the pre-setup User account with SQL Server Admin and dbo privileges in an Active Directory account to allow it to see various places on our Network as well.
But we don't want it to take the resources away from the main server. The PowerShell script that was to be run would backup the database Log file and then use the another server to asynchronously copy the file itself and not make the SQL Server Job/PowerShell wait for it. We wanted it to happen right after the backup.
Here is my new way, using WMI, using Windows Integrate Security:
$ComputerName = "kithhelpdesk"
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -Command "Copy-Item -Path \\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak -Destination \\YourShareDestination\YourDatabase_2018-08-07_11-45.log.bak"'
Here is my new way using passed in Credentials, and building arg list variable:
$Username = "YouDomain\YourDomainUser"
$Password = "P#ssw0rd27"
$ComputerName = "RemoteServerToRunOn"
$FromFile = "\\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ToFile = "\\YourShareDestination\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ArgumentList = 'powershell.exe -Command "Copy-Item -Path ' + $FromFile + ' -Destination ' + $ToFile + '"'
$SecurePassWord = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $Username, $SecurePassWord
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList $ArgumentList -Credential $Cred
We think that this above one is the preferred one to use.
You can also run a specific powershell that will do what you want it to do (even passing in parameters to it):
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -file "C:\PS\Test1.ps1"'
This example could be changed to pass in parameters to the Test1.ps1 PowerShell script to make it more flexible and reusable. And you may also want to pass in a Credential like we used in a previous example above.
Help configuring WMI:
I got the main gist of this working from: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1
But it may have also needed WMI configuration using:
https://helpcenter.gsx.com/hc/en-us/articles/202447926-How-to-Configure-Windows-Remote-PowerShell-Access-for-Non-Privileged-User-Accounts?flash_digest=bec1f6a29327161f08e1f2db77e64856b433cb5a
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting?view=powershell-5.1
Powershell New-PSSession Access Denied - Administrator Account
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 (I used to get how to call Invoke-WmiMethod).
https://learn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help?view=powershell-6 (I used to get syntax of command line)
I didn't use this one, but could have: How to execute a command in a remote computer?
I don't know for sure if all of the steps in the web articles above are needed, I suspect not. But I thought I was going to be using the Invoke-Command PowerShell statement to copy the files on a remote server, but left my changes from the articles above that I did intact mostly I believe.
You will need a dedicated User setup in Active Directory, and to configure the user accounts that SQL Server and SQL Server Agent are running under to give the main calling PowerShell the privileges needed to access the network and other things to, and can be used to run the PowerShell on the remote server as well. And you may need to configure SQLServer to allow SQL Server Jobs or Stored Procedures to be able to call PowerShell scripts like I did. But this is outside the scope of this post. You Google other places on the internet to show you how to do that.

Open remote location from PowerShell as different user

I need to open some remote folder a lot of times, and I usually use start in powershell this way
start \\myserverXXX\some_hidden_drive$\some_folder
Sometimes I need to use an administrator account, and I would expect to be prompted to insert different credential, but i get an error instead. Am I missing something?
Use the credential option as follows
start \\myserverXXX\some_hidden_drive$\some_folder -Credential $(Get-Credential)
This will prompt you to enter different credentials
Have you tried mapping a drive using those credentials, then opening it? I don't have a place to test this at the moment.
New-PsDrive -Name X -PSProvider Filesystem -Root \\myserverXXX\some_hidden_drive$\some_folder -credential $(get-credential);
Invoke-Item X:

Copy file remotely with PowerShell

I am writing a PowerShell script that I want to run from Server A.
I want to connect to Server B and copy a file to Server A as a backup.
If that can't be done then I would like to connect to Server B from Server A and copy a file to another directory in Server B.
I see the Copy-Item command, but I don't see how to give it a computer name.
I would have thought I could do something like
Copy-Item -ComputerName ServerB -Path C:\Programs\temp\test.txt -Destination (not sure how it would know to use ServerB or ServerA)
How can I do this?
From PowerShell version 5 onwards (included in Windows Server 2016, downloadable as part of WMF 5 for earlier versions), this is possible with remoting. The benefit of this is that it works even if, for whatever reason, you can't access shares.
For this to work, the local session where copying is initiated must have PowerShell 5 or higher installed. The remote session does not need to have PowerShell 5 installed -- it works with PowerShell versions as low as 2, and Windows Server versions as low as 2008 R2.[1]
From server A, create a session to server B:
$b = New-PSSession B
And then, still from A:
Copy-Item -FromSession $b C:\Programs\temp\test.txt -Destination C:\Programs\temp\test.txt
Copying items to B is done with -ToSession. Note that local paths are used in both cases; you have to keep track of what server you're on.
[1]: when copying from or to a remote server that only has PowerShell 2, beware of this bug in PowerShell 5.1, which at the time of writing means recursive file copying doesn't work with -ToSession, an apparently copying doesn't work at all with -FromSession.
Simply use the administrative shares to copy files between systems.
It's much easier this way.
Copy-Item -Path \\serverb\c$\programs\temp\test.txt -Destination \\servera\c$\programs\temp\test.txt;
By using UNC paths instead of local filesystem paths, you help to
ensure that your script is executable from any client system with
access to those UNC paths. If you use local filesystem paths, then you
are cornering yourself into running the script on a specific computer.
Use net use or New-PSDrive to create a new drive:
New-PsDrive: create a new PsDrive only visible in PowerShell environment:
New-PSDrive -Name Y -PSProvider filesystem -Root \\ServerName\Share
Copy-Item BigFile Y:\BigFileCopy
Net use: create a new drive visible in all parts of the OS.
Net use y: \\ServerName\Share
Copy-Item BigFile Y:\BigFileCopy
Just in case that the remote file needs your credential to get accessed, you can generate a System.Net.WebClient object using cmdlet New-Object to "Copy File Remotely", like so
$Source = "\\192.168.x.x\somefile.txt"
$Dest = "C:\Users\user\somefile.txt"
$Username = "username"
$Password = "password"
$WebClient = New-Object System.Net.WebClient
$WebClient.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$WebClient.DownloadFile($Source, $Dest)
Or if you need to upload a file, you can use UploadFile:
$Dest = "\\192.168.x.x\somefile.txt"
$Source = "C:\Users\user\somefile.txt"
$WebClient.UploadFile($Dest, $Source)
None of the above answers worked for me. I kept getting this error:
Copy-Item : Access is denied
+ CategoryInfo : PermissionDenied: (\\192.168.1.100\Shared\test.txt:String) [Copy-Item], UnauthorizedAccessException>
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand
So this did it for me:
netsh advfirewall firewall set rule group="File and Printer Sharing" new enable=yes
Then from my host my machine in the Run box I just did this:
\\{IP address of nanoserver}\C$