How to obtain UNC drive info on "Disconnected Network Drive" - powershell

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

Related

Any way to identify the Computer's OU information from local WMI or Registry

I'm looking for a way to obtain the OU information of a computer from its local WMI or Registry. I know there are ways to pull the OU information from a host using PowerShell and AD commandlets... Afraid every time we execute the commands, it will hit the domain controller and pull the information. If we run similar commands simultaneously on a large number of computers, it would spike the number of connections to Domain Controllers. We would like to avoid such cases and see if we can find a way to obtain the OU information if it's stored locally in the host.
I did find a few sample codes from other responses and they are working well, however, I feel they are retrieving the information from Domain Controller (sorry if I misunderstood). Could someone confirm if this is the only option we have to use or is there any alternative solution?
Sample Code:
([adsisearcher]"(&(name=$env:computername)(objectClass=computer))").findall().path
(or)
Import-Module ActiveDirectory -Force;
Get-ADComputer $env:computername | select -ExpandProperty DistinguishedName
Thanks,
Nana

Powershell to find machine that created a file

I have a script that monitors the filesystem using FileWatcher.IO in Powershell.
Currently it finds the user that made the file with:
$owner = (Get-Acl $path).Owner
And it finds the computer that the file was made on with:
$Computer = get-content env:computername
But I'd also like to obtain what machine the file was created from. For instance, if a user is logged into a terminal server, I can see the file is made on the terminal server. But I want to know the host name of the local machine that made the file on the terminal server.
Is this possible? I've been searching the msdn PSEventArgs Class page without much success.
That information is not going to be stored in the file or its metadata, so no there's no straightforward way to get at it.
By the way, you can just use $env:computername directly as a variable; there's no need to use Get-Content.

Get HDD serial numbers using Powershell

I am archiving a large number of HDD's at my company, and I have a powershell script that grabs the hostname and user list from a Windows OS installation, and I would like to programatically find the serial number of the drive as well. I have the following bit of Powershell code (mostly completed) that should do this, but there's a complication as well.
$Disks = Get-WMIObject -class win32_PhysicalMedia
$SerialNumber = foreach($Disk in $Disks) {IF ($Disk.SerialNumber -ne ' WD-WCC2EAV91692') {[do something here]}}
I am connecting the drives with a USB HDD dock, and it seems that if the computer is booted with the drive connected internally (via SATA cables, I haven't tested externally yet), then the SerialNumber field is populated. However, if I connect it after the computer has booted up, the SerialNumber field is always blank. Is there a way to have the computer re-scan for this info when I connect the drive, or is this info only gathered at boot-up, for example, by the BIOS or something?
AFAIK the SerialNumber is optional and provided by the driver. So if the USB-dock driver is not providing the information to Windows, then there's no easy way to retrieve it.
This thread (look for "Maxim Shatskih") says that IOCTL_SCSI_PASS_THROUGH is supported by USBSTOR, so it would be possible to write or find a program that can get the serial number from a USB attached drive, by passing the appropriate SCSI command to the drive (get mode page 80h).
A package that may do what you need is sg3_utils for Windows (it was originally written for Linux but ported to Windows).
I just tested booting the computer up with the HDD in the USB dock, and I got the same result. Technically, the SerialNumber field wasn't blank, but was all zero's instead of the actual serial number, which is probably just the same difference. It's seeming like it may be more work than it's worth to do this as a part of the script (assuming it's even possible), so I will likely just continue scanning the SN barcode into the script. It's an extra step, but only takes a couple seconds.
Thanks everyone for the input.

Distinguish Windows services with the same ProcessName

I am adjusting a monitoring system which checks if a service is running or not. It does that by checking the process name and it's memory consumption. Once it drops below 1 MB an alert is triggered. Also I use the memory usage value to display it in a graph. So checking and notifying is not the only purpose.
Currently I have 5 Windows services using the same ProcessName and I don't know how to make my script distinguish them. The ServiceName for each service is of course different and the path to the executable as well.
When I run get-process I see them all, but I don't see an option here distinguish them. Using get-service doesn't help much either, because it returns name, displayed name and status. Somehow I would love to combine the entries to see the memory usage by service name, not by process name.
You say that the path to executable is different - this way you can distinguish the processes by querying path property. Should they be equal, you can also query StartInfo object of a process to get Arguments property to discern from one another. But the best way to get correct process instances will be to query WMI objects of type Win32_Service to filter your services out, this way you can find if one of them is stopped as well, and then get the process by passing the ProcessId property of the WMI service object. For running services, the PID will be valid. An example (which only filters by service name):
gwmi win32_service | ? {$_.name -eq "wsearch"} | % {get-process -id $_.processid}
Note that there is a possibility that one process will handle more than a single service, this is called "Shared service process" and is visible in Get-Service output as ServiceType property of the returned service, the value Win32SharedProcess (0x20) indicated the underlying PID can be shared, although it's not always the case. The most known shared service process is svchost.exe which also has a sort of a namespace to determine which process should host a certain service, passed to it as a command line parameter.

Determine where script is being executed from

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!