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
Related
I am able to map a network path with the console command
net use x: https://some.server.xy/path/to/directory
However, when I tried to map the network drive in PowerShell (before I assigned it with net use x: ...) with
new-psDrive v fileSystem https://some.server.xy/path/to/directory
I got the error message
new-psDrive : The specified drive root "https://some.server.xy/path/to/directory" either does not exist, or it is not a folder.
Apparantly, my assumption that those two commands would have the same effect was wrong.
The question is: what is PowerShell's equivalent for using net use ...?
Copied from Stack Exchange: Map Network Drive to a WebDAV Server via PowerShell:
Here is a working example of me mounting the Sysinternals WebDAV site to my S: drive:
[String]$WebDAVShare = '\\live.sysinternals.com\Tools'
New-PSDrive -Name S -PSProvider FileSystem -Root $WebDAVShare
Notice you need to use the UNC format, not the http:// prefix.
Also you need to make sure that the WebClient service is running on your computer.
If you wanted to confirm that a server supports WebDAV, you could do:
(Invoke-WebRequest http://live.sysinternals.com -Method Options).Headers.DAV
And if that returns something like 1,2,3 then the server supports various versions of WebDAV. (Although the server administrator may have disallowed the Options verb.)
Currently, I run the following command to fetch the files to my local system.
Get-SCPFile
-ComputerName $server
-Credential $credential
-RemoteFile ($origin + $target + ".csv")
-LocalFile ($destination + $target + ".csv")
It works as I'd like (although it sucks that I can't copy multiple files by regex and/or wildcard). However, after the operation has been carried out, I'd like to move the remote files to another directory on the remote server so instead of residing in $origin at $server, I want them to be placed in $origin + "/done" at the same server. Today, I have to use PuTTY for that but it would be so much more convenient to do that from PS.
Googling gave me a lot of material but I couldn't make it work. At the moment, I'm not sure if I'm specifying the path incorrectly somehow or if it's not possible to use the plain commands when working against an external, secured, Unix-server.
For copying files, I can't use Copy-Item, hence the function Get-SCPFile. I can imagine that remote moving, renaming and listing the items isn't possible neither for the same reason (whatever that reason is).
This example as well as this one produce error cannot find path despite the value being used for copying the file successfully with the script at the top. I'm pretty sure it's a misleading error message (not being enitrely sure, though).
$file = "\\" + $server + "" + $origin + "" + $target + ".csv"
# \\L234231.vds.afm.se/var/trans/ut/drish/sxx/meta001.csv
Remove-Item $file -force
Many answers (like this) are very simple, which supports my theory that the combination of Unix and secure raise an extra challenge. Perhaps I'm wording the question insufficiently well.
There's also more advanced examples, still not working, just hanging up the window with no error messages. I feel my competence prevents me from estimating the degree of screwuppiness in this approach.
In PowerShell you can create a PowerShell Session (PSSession) from your System remotly on another System (and into another Session on your System but thats details... ) and execute your commands there.
You can create a PSSession with New-PSSession but a lot of cmdlets have a-ComputerName parameter (or something similar) so that they can be executed remotley without creating a PSSession first.
A PSSession can be used with Enter-PSSession to get an interactive Session or with Invoke-Command to execute a ScriptBlock. That way you could test your Remove-Item command directly on the target server. Depending on the setup you might need to use Linux syntax within the remote session.
Here are some more infos about_PSSessions and using it with SSH to connect to Linux
I'm trying to copy a file to a specific folder on one of n hosts (hostA, hostB etc.), but i don't know the full path of the folder.
If I don't use a credential (which I have to do) I can e.g.
test-path -path \\hostA\d$\*\targetFolder ...and hit D:\blah\targetFolder
I could use the credential with new-psdrive, but then I can't map to a wildcarded path. I could also invoke-command, but then I'd have to work out a way to get the file from the sourceHost...
This is for a TFS/AzureDevops pipe.
Using New-PSDrive, map a (non-persistent, PS-only) drive to the admin share \\hostA\d$ itself, and then use that drive for wildcard-based path testing:
# Define a PS-only RemoteD: drive that maps to \\hostA\d$,
# using the specified credentials.
New-PSDrive RemoteD FileSystem \\hostA\d$ -Credential (Get-Credential)
# Use paths based on RemoteD: for wildcard-based testing.
Test-Path RemoteD:\*\targetFolder
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
}
I have a script that will send items to the recycle bin (if selected) or delete items permanently. If the script is run locally, the recycle piece works properly.
However, if it's run from a different computer - in this case, my local machine runs the script against a shared folder on a server - the delete is permanent, and doesn't get sent to the recycle bin. The script (in a prior run) makes a decision about WHAT to delete by first setting the Archive bit to TRUE and then (after seeing how many backups it is to retain) un-setting the Archive bit for items to be deleted on the next execution of that same script.
My thought was to alter the main script to mark the files for deletion, but only do the physical action of deleting the file(s) only when the script was being run locally, or to put the Recycle script (by itself) as a Task on the server that would delete & send the item to the Recycle Bin that would run at a set interval.
My questions-
In Powershell (using 2.0) how do you determine the source computer
vs the target computer? In this case, the script is being run from
MyPC, and it's target is Server1.
The script will run whether the target is a mapped drive (Drive Y:),
or if it's targeted by the servername (\Server1). How can you
distinguish the above question in both of these cases?
You can get the local computer name with $env:COMPUTERNAME. Use it to compare the value against the target server name.
For each file, you'd have to check first if the drive is a mapped drive, if it is, get the server name from the wmi instance and compare it to $env:COMPUTERNAME.
You can get a file's Drive qualifier with the Split-Path cmdlet:
PS> $drive = Split-Path Q:\test.txt -Qualifier
PS> $drive
Q:
And then get the server name with WMI:
PS> (gwmi win32_logicaldisk -filter "drivetype=4 and deviceid='$drive'").ProviderName.Split('\')[2]
Server1
The OP wrote:
#Shay - Thanks for your help. I've learned a great deal from many posts by you on various Powershell sites.
I was able to use almost everything you suggested, and only had to add an extra line of code to make it work. I checked the property ([System.Uri]$markedFile).IsUnc to determine if the filename I've read is a UNC name.
It returns False if the drive is mapped, and True if it is UNC. From that, I'm able to get the servername & make a comparison to the environment. Code follows.
$markedFile = "\\Server1\foldername1\Error.log"
#$markedFile = "Y:\foldername1\Error.log"
$TargetComputer = $null
$thisComputer = Get-Content env:computername
if (Test-Path $markedFile) { # if file exists
if (([System.Uri]$markedFile).IsUnc) { # if it's a UNC name & not a mapped drive name
$TargetComputer = ([System.Uri]$markedFile).Host
}
else { #file is not a UNC name, it must be a mapped drive
$drive = Split-Path $markedFile -Qualifier
$TargetComputer = (gwmi win32_logicaldisk -Filter "drivetype=4 and deviceid = '$drive'").Providername.split('\')[2]
}
}
The above code works either way. Thank you again for your help!