I'm working on a script to get my ACLs for all of the shares in my network. I have three separate UNC paths that I am running this on. Two of the three are working perfectly, returning all child items and permissions and such. However, the third UNC path is returning the following error:
Get-ChildItem : Cannot find path '\\storagesrvr' because it does not exist.
I have verified that the location is available by using Explorer. What I find interesting is that if I use GCI on any of the sub-shares of that path, it works. What could possibly be preventing GCI from detecting the root of the share?
EDIT (as requested from comments): The other two shares that I had no issues with were named like \\networkpath\share. But because I was only looking at the root, GCI was not working.
As I mentioned in the comments \\computername is only a partial UNC path (check the UNC grammar in the [MS-DTYP] Windows Data Type specification).
Explorer "knows" this, and so it does some black magic in the background to allow you to browse the shares on the remote computer.
You can emulate this, by querying the Win32_Share WMI instances on the remote machine:
foreach($Share in Get-WmiObject Win32_Share |?{$_.Name -ne 'IPC$'}){
Get-ChildItem "\\$($Share.__SERVER)\$($Share.Name)"
}
You can list shares by calling:
net view \\<computername>
source:
PowerShell Get List Of Folders Shared
The error message is literally correct. \\storageserver is not a path. It is two backslashes followed by a computer name.
Append a share name to it, and it becomes a path; e.g. \\storageserver\sharename.
Related
I am working on a project that utilizes a PowerShell script that creates a new login on a remote SQL Server (SSMS) and then checks to see if a particular folder exists on the server. If the folder does not already exist, the script will create that folder.
The issue I am having is that I cannot verify whether or not the folder exists since the path I am testing is a UNC path of the form "\\server\Files\Log". I have tried many different solutions that I have found through a couple hours of searching online, and all solutions return FALSE even though I am testing a server and folder I know already exist.
I am using PowerGUI to write my script and my system is using PowerShell v5. What I have tried so far:
Test-Path $path (where $path has been set to \\server)
Test-Path "filesystem::\\Srv"
[System.IO.Directory]::Exists($path)
I even tried [System.IO.Directory]::Exists('G:\') using all of the
letters I have network servers mapped to to see if I needed to map to the drives to make it work (all returned FALSE)
What am I missing here? Any thoughts on this topic would be greatly appreciated as I have been grinding on this for a while with no progress being made.
EDIT: For anyone who might stumble upon this later, please read the comments, which I found to be super helpful. My main issue was that I was running PowerShell as an administrator which does not have the same permissions as my normal user account. Also note that Test-Path \\server alone does not work, a folder must also be referenced.
You already have the correct answer:
Test-Path $path
or
Test-Path \\server.domain.tld\ShareName
If Test-Path is returning false, I can think of three things that could be wrong:
The share does not exist on that server, or at least with the name you expect
Your user does not have permission to read that share
You are specifying the short name of the server, and you need the FQDN to resolve it. This is common in multidomain environments.
After re-reading your question, it looks like you might be running Test-Path \\server. You cannot check for the existence of a server this way, you have to specify both the server and the share name at a minimum. If you want to know that a server exists and is online, use Test-Connection (assuming you are able to ping this server in the first place). Here is an example of using Test-Connection:
$serverName = 'server.domain.tld'
$sharePath = 'ShareName' # you can append more paths here
if( Test-Connection $serverName 2> $null ){
Test-Path "\\${serverName}\${sharePath}"
}
I used to have an issue where the file existed, but test-path is returning false. I put test-path in a loop that checks a maximum of 10 x, with a one sec pause in between. The script works fine now. If on the first attempt it does not find the file on the second or third it does. Not sure why it returns false on the first attempt.
I'm working on a script to get my ACLs for all of the shares in my network. I have three separate UNC paths that I am running this on. Two of the three are working perfectly, returning all child items and permissions and such. However, the third UNC path is returning the following error:
Get-ChildItem : Cannot find path '\\storagesrvr' because it does not exist.
I have verified that the location is available by using Explorer. What I find interesting is that if I use GCI on any of the sub-shares of that path, it works. What could possibly be preventing GCI from detecting the root of the share?
EDIT (as requested from comments): The other two shares that I had no issues with were named like \\networkpath\share. But because I was only looking at the root, GCI was not working.
As I mentioned in the comments \\computername is only a partial UNC path (check the UNC grammar in the [MS-DTYP] Windows Data Type specification).
Explorer "knows" this, and so it does some black magic in the background to allow you to browse the shares on the remote computer.
You can emulate this, by querying the Win32_Share WMI instances on the remote machine:
foreach($Share in Get-WmiObject Win32_Share |?{$_.Name -ne 'IPC$'}){
Get-ChildItem "\\$($Share.__SERVER)\$($Share.Name)"
}
You can list shares by calling:
net view \\<computername>
source:
PowerShell Get List Of Folders Shared
The error message is literally correct. \\storageserver is not a path. It is two backslashes followed by a computer name.
Append a share name to it, and it becomes a path; e.g. \\storageserver\sharename.
I'm fairly new to PowerShell and am running into a problem.
I want to do the following:
Get list of permissions/users on a single folder on a different server than where I am running my PowerShell window from.
Current command failing:
Get-acl -path "\\servername\folder"
Error Message:
Get-acl : Cannot find path '\\servername\folder' because it does not exist
Does this command only work on the local machine?
It turns out with the way permissions/authentications are setup in my environment prevented my code from working.
Here are the steps I took to verify if I could connect to the server:
Test-Path \\server\folder
This returned "False", which is why my code was breaking.
The work around I used was this:
#Step 1: remotely connect to server
Enter-PSSession -ComputerName servernamegoeshere
#Step 2: get list of permissions on folder and save to csv
get-acl E:\foldernamehere |
select -expand access |
export-csv C:\Users\usernamegoeshere\Documents\listofperms.csv |
#Step 3: close remote connection
Exit-PSSession
I still had to remote into the server and copy the csv to the location I wanted because again, any copy command to another server/share in PowerShell would not work due to permission/authentication issues.
This article explains authentication/permissions a bit better than I can:
http://blogs.technet.com/b/heyscriptingguy/archive/2012/11/14/enable-powershell-quot-second-hop-quot-functionality-with-credssp.aspx
Second way to do this with less code and not having to create a remote session thanks to user Ansgar Wiechers:
Invoke-Command -Computer server -ScriptBlock {get-acl E:\folder |
select -expand access } |
export-csv \\server\folder\accesslist.csv
With PowerShell, there are many ways to do one thing...I think this way is best/most simple! Thanks!
The command works on UNC paths as well, but UNC paths are slightly different from local paths. You need an access point to enter the file system of a remote host. For SMB/CIFS access (via UNC paths) that access point is a shared folder, so you need a path \\server\share or \\server\share\path\to\subfolder.
With an admin account you could use the administrative shares (e.g. \\server\C$\Users\Administrator), otherwise you need to create a share first.
We run some processes in a distributed computing environment. Processes on one machine need to communicate information with processes on other machines. One of those piecies of information is the location of certain files. Thus, a process on one machine may have put information into a particular file on a particular network share, and it needs to communicate the location to a process on another machine.
We have no problem with the communication part. The problem is with determining the "location" information that a machine need to disseminate. File paths involving drive mappings are clearly useless: different machines will have differing drive mappings. Thus, what we need to communicate it the full UNC path name.
For the most part, we can obtain that information easily. One place where we are having problems is in a powershell script that needs to obtain this information. Currently, we use the following code:
$l_logicalDisk = Gwmi Win32_LogicalDisk -filter "DeviceID = '$l_currentDrive'"
if ( $l_logicalDisk.DriveType -eq 4 )
{
$l_base = $l_logicalDisk.ProviderName
}
and $l_base provides the \\computername\share information. However, in certain circumstances, this fails. At times, for some unknown reason, a mapped drive will appear as "Disconnected Network Drive" in Explorer.exe, even though the drive and all its files are accessible. (In fact, the script that is running is even located on the supposed "Disconnected Network Drive".) In this situation, the ProviderName field of the logical disk information is blank. Nothing seems to flip the status from "Disconnected Network Drive", nor have I found any way to update the ProviderName information.
So, does anyone know either (1) how to "reconnect" a disconnected network drive from within powershell or (2) how in Powershell to obtain the UNC path information for a directory in a more reliable method that outlined above? Thanks.
You can always ask the registry, this should work on disconnected drives (where $DrvLtr equals the desired network mapped drive letter such as Z or M):
Pushd
cd HKCU:
$UNC=(gci network|?{$_.Name -match "$DrvLtr"}|%{Get-ItemProperty -Path $_}).RemotePath
Popd
$UNC should then be a string with a value like "\Server01\FileShare$" which I think is what you're going for. Then you can just do a
$Path.Replace("$DrvLtr`:",$UNC)
And you're all set
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!