Local path from shared path: Powershell - powershell

How to find the local path of a shared path.
My shared path is \\somemachine\shared\scripts\testing
Its local path is D:\myshares\scripts\testing
Thanks!

Using WMI, you can get a list of shares with their local path equivalents:
PS C:\> gwmi Win32_Share
Name Path Description
---- ---- -----------
ADMIN$ C:\Windows Remote Admin
C$ C:\ Default share
IPC$ Remote IPC
You would just need to match up the Name property to your share path, then replace it to get the local path on that server using the Path property of the results:
$name = "shared"
$share = (gwmi Win32_Share | ? { $_.Name -eq $name }
$path = $share.Path + "\scripts\testing"
Note: You can also pass the -ComputerName parameter to the gwmi cmdlet to run the command against another computer. You may also need to pass the -Credential parameter to supply valid credentials.

Just in case you don't have access to WMI, this can also be accomplished using the net command:
PS C:\> net share
Share name Resource Remark
------------------------------------------------------------------------------
C$ C:\ Default share
IPC$ Remote IPC
ADMIN$ C:\Windows Remote Admin
The command completed successfully.

Related

Powershell returns different information using remote connection

On my target computer in PowerShell I run command
$FolderSize =(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum
and I get a value of 0.76 gb, which accurately corresponds to the compressed size of the folder on disk. However, when I try to run the command on a remote computer using
$folderSize = Invoke-Command -ComputerName "computername" {(Get-ChildItem -Path "C:\Users\JDoe" -Recurse -force -ErrorAction SilentlyContinue | Measure-Object -Property Length -sum).sum}
I get a different, MUCH larger number, 17 gb.
I tried running the first command in a pssession but still get the 17gb result. I also tried using
psexec \\\computername powershell "(Get-ChildItem "C:\Users\JDoe" -force -Recurse -ErrorAction SilentlyContinue | Measure-Object length -sum).sum" but still get the larger number.
I don't understand why the results obtained remotely are different than the actual size of the folder when I examine it locally. At least all the remote results are consistent, which tells me they are all measuring the same thing.
This is due to a junction in AppData\Local named Application Data that points back to AppData\Local
It appears that you can access this junction remotely (even from explorer using \\COMPUTER01\C$\Users\JDoe\AppData\Local\Application Data) so this is why you're getting different sizes, as it's recursively counting the same stuff up to the MAX_PATH limit.
Compare the following command's outputs on remote vs local:
Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force
Local
PS C:\> Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force
Get-ChildItem : Access to the path 'C:\Users\JDoe\AppData\Local\Application Data' is denied.
At line:1 char:1
+ Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Forc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\users\JDoe\A...plication Data\:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
Remote
PS C:\> Invoke-Command -ComputerName COMPUTER01 -ScriptBlock { Get-ChildItem 'C:\Users\JDoe\AppData\Local\Application Data' -Force }
Directory: C:\Users\JDoe\AppData\Local\Application Data
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
d--hsl 4/16/2020 4:46 PM Application Data COMPUTER01
d----- 10/31/2019 9:43 AM ConnectedDevicesPlatform COMPUTER01
d----- 10/31/2019 9:52 AM ElevatedDiagnostics COMPUTER01
d----- 10/31/2019 9:43 AM Google COMPUTER01
d--hsl 4/16/2020 4:46 PM History COMPUTER01
d----- 4/16/2020 4:50 PM Microsoft COMPUTER01
d----- 9/16/2019 8:14 PM Microsoft Help COMPUTER01
d----- 10/31/2019 9:43 AM MicrosoftEdge COMPUTER01
d----- 10/31/2019 9:53 AM OpenShell COMPUTER01
d----- 4/16/2020 4:47 PM Packages COMPUTER01
d----- 10/31/2019 9:43 AM PlaceholderTileLogoFolder COMPUTER01
d----- 10/31/2019 9:43 AM Publishers COMPUTER01
d----- 3/18/2019 11:52 PM Temp COMPUTER01
d--hsl 4/16/2020 4:46 PM Temporary Internet Files COMPUTER01
d----- 10/31/2019 9:43 AM VirtualStore COMPUTER01
You will need to recurse separately from Get-ChildItem by using a recursive function like the one in this answer.
Thanks for all the suggestions! Ultimately, I opted to use Sysinternals "du" app and capture the output in a remote job, so as to minimize network traffic.
Thanks again!
CrookedJ's helpful answer provides the crucial pointer:
Due to the network-type logons that PowerShell remoting uses - see this GitHub issue - PowerShell code that runs remotely unexpectedly has the required privileges to recurse into the hidden system junctions. However, these hidden junctions exist solely for backward compatibility with pre-Vista Windows versions and are not meant to be traversed themselves: they simply redirect to the current locations of the well-known folders they represent.
E.g., the hidden "$HOME\My Documents" junction points to "$HOME\Documents" - see this article for background information.
Locally executing code - even if run as admin - is by design not allowed to access the contents of these hidden junctions.
When you use Get-ChildItem -Recurse:
Windows PowerShell reports access-denied errors while encountering these hidden junctions during recursive traversal, because it tries to recurse into them.
PowerShell [Core] v6+ more sensibly quietly skips these junctions during recursive traversal - both in local and remote execution, so your problem wouldn't arise. Generally, directory symlinks/junctions are not followed by default, unless -FollowSymlink is specified; even then, however, no error occurs - only a warning is emitted for each hidden junction, in recognition that the redirected-to real directories have already been traversed.
In Windows PowerShell, your remotely executing code therefore counts the files in certain directories (at least) twice - once as the content of the hidden junction, and again in the actual directory pointed to.
Therefore, there are two potential solutions:
If the target machine has PowerShell [Core] v6+ installed and remoting enabled, target it with your remoting command (which you can do even when calling from Windows PowerShell:
Simply add a -ConfigurationName PowerShell.<majorVersion> argument to your Invoke-Command call, e.g., -ConfigurationName PowerShell.7 for PowerShell [Core] 7.x versions.
Otherwise - if you must target Windows PowerShell - you need a workaround, which in your case is to use a custom Get-ChildItem variant that explicitly skips the hidden junctions during recursion:
# Note:
# * Hidden items other than the hidden junctions are invariably included.
# * (Other, non-system) directory reparse points are reported, but not recursed into.
# * Supports only a subset of Get-ChildItem functionality, notably NOT wildcard patterns
# and filters.
function Get-ChildItemExcludeHiddenJunctions {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param(
[Parameter(ValueFromPipelineByPropertyName, Position = 0)] [Alias('lp', 'PSPath')]
[string] $LiteralPath,
[Parameter(ParameterSetName = 'DirsOnly')]
[switch] $Directory,
[Parameter(ParameterSetName = 'FilesOnly')]
[switch] $File,
[switch] $Recurse
)
# Get all child items except for the hidden junctions.
# Note: Due to the -Attributes filter, -Force is effectively implied.
# That is, hidden items other than hidden junctions are invariably included.
$htLitPathArg = if ($LiteralPath) { #{ LiteralPath = $LiteralPath } } else { #{ } }
$items = Get-ChildItem #htLitPathArg -Attributes !Directory, !Hidden, !System, !ReparsePoint
# Split into subdirs. and files.
$dirs, $files = $items.Where( { $_.PSIsContainer }, 'Split')
# Output the child items of interest on this level.
if (-not $File) { $dirs }
if (-not $Directory) { $files }
# Recurse on subdirs., if requested
if ($Recurse) {
$PSBoundParameters.Remove('LiteralPath')
foreach ($dir in $dirs) {
if ($dir.Target) { continue } # Don't recurse into (other, non-system) directory reparse points.
Get-ChildItemExcludeHiddenJunctions -LiteralPath $dir.FullName #PSBoundParameters
}
}
}
To use this function in a remote script block, you'll (also) have to define it there:
# Assuming the Get-ChildItemExcludeHiddenJunctions function is already defined as above:
# Get a string representation of its definition (function body).
$funcDef = "${function:Get-ChildItemExcludeHiddenJunctions}"
$folderSize = Invoke-Command -ComputerName "computername" {
# Define the Get-ChildItemExcludeHiddenJunctions function in the remote sesson.
${function:get-ChildItemExcludeHiddenJunctions} = $using:funcDef
(Get-ChildItemExcludeHiddenJunctions "C:\Users\JDoe" -Recurse -File |
Measure-Object -Property Length -Sum).Sum
}

Saving Active Directory Configuration settings to a file

I'm using my machine to run a script on the Domain Controller server using Enter-PSSession. It all works except, I can't save the outputs from the script on my local machine.
I want to save the outputs from the script as objects in my local machine in a csv format (Not on the Domain Controller server).
What I'm trying to do is save results from running commands like Get-ADDomainController etc..
Can someone please help me with this?
As for this …
I can't save the outputs from the script on my local machine.
… sure you can. Just create a log file as part of your session and copy that file back to your workstation for review, or just use the *-Transcript cmdlets to that creates a file automatically that you can copy over. The transcript will record everything that happens in the sessions.
Get-Command -Name '*transcript*' | ft -a
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Start-Transcript 3.0.0.0 Microsoft.PowerShell.Host
Cmdlet Stop-Transcript 3.0.0.0 Microsoft.PowerShell.Host
# get function / cmdlet details
(Get-Command -Name Start-Transcript).Parameters
Get-help -Name Start-Transcript -Full
Get-help -Name Start-Transcript -Online
Get-help -Name Start-Transcript -Examples
Or, don't use the interactive Enter-PSSession (explicit PowerShell Remoting) that puts you directly on the DC. Use a Implicit PSRemoting session, using New-PSSession and proxy the AD cmdlets to your machine for use.
$SessionAD = New-PSSession -ComputerName ''dc01.contoso.com
Invoke-Command $SessionAD -Command {Import-Module ActiveDirectory}
Import-PSSession $SessionAD -Module ActiveDirectory | Out-Null
$ADUSers = Get-ADuser -Filter *
$var = $ADUSers | Select-Object -Property Name, SamaccountName | Out-GridView -OutputMode Single
$GroupsMember = Get-ADUser -Filter ('Name -eq "' + $var.Name + '"') -Property MemberOf |
Select -ExpandProperty MemberOf |
Get-ADGroup -Property MemberOf |
Select Name
$GroupsMember
Get-PSSession | Remove-PSSession
Then you can run ADDS cmdlets as if they are actually on your machine and results are on your machine, or if you are on Window 8 or higher, just download and install (Win 7 - 8) / enable the RSAT tools (Win 10) directly and use them.
Remoting the Implicit Way
PowerShell Implicit Remoting: Never Install a Module Again
Also, take a look and Invoke-Command for running command locally or remotely.

Get-WMIObject returning multiple responses in a script, only one when run alone

I'm trying to script powershell to reach out to all AD Computers and pull a list of shares. I'm seeing some strange behavior with Get-WMIObject.
The script:
Import-Module ActiveDirectory
$Computers = Get-ADComputer -Filter * -SearchBase "Some OU" |
Where-Object {
$_.Name -match "-LT$" -or
$_.Name -match "-PC$" -or
$_.Name -match "-VPC$"
} |
Select-Object Name -ExpandProperty Name |
Sort
$Computers | ForEach-Object {
Write-Host $_
Write-Host "========================="
Get-WMIObject -Class Win32_Share -Computer $_
}
Normally, the output from the gwmi command looks like this:
Name Path Description
---- ---- -----------
ADMIN$ C:\Windows Remote Admin
C$ C:\ Default share
IPC$ Remote IPC
But instead, for that same computer I get this output:
...
[Computername]
=========================
Name Path Description
---- ---- -----------
ADMIN$ C:\WINDOWS Remote Admin
C$ C:\ Default share
IPC$ Remote IPC
print$ C:\WINDOWS\system32\spool\drivers Printer Drivers
ADMIN$ C:\WINDOWS Remote Admin
C$ C:\ Default share
IPC$ Remote IPC
print$ C:\WINDOWS\system32\spool\drivers Printer Drivers
ADMIN$ C:\Windows Remote Admin
C$ C:\ Default share
IPC$ Remote IPC
...
These two outputs are from the same computer. I've also output the computer name list, and I'm not missing a computer, so I don't think that they were combined.
Any clues?

Finding path of process on remote machine

You can use the following in Powershell to obtain the full path to where a specific process is running:
Get-Process | where{$_.Name -like "*iexplore*"} | Select Path
If I want to find this path for a service on a remote machine, I thought I could just utilise the following:
Get-Process -ComputerName $MyServer | where{$_.Name -like "*iexplore*"} | Select Path
However, this doesn't return anything. I can see that I can find the service itself with some details on current usage etc. but I cannot find the path for where the .exe file is located. (I also noticed I cannot see how many CPUs the process is using either).
Is there a way to find the path for the process?
Get-Process missing this, but you can use WMI:
Get-WmiObject -Class win32_process -ComputerName $MyServer -Filter 'name like "%iexplore%"' | select path

powershell Get-Process with ComputerName is missing Path

I want to get a list of processes under specific folder on some remote machine and kill them. However, if I add -ComputerName, Get-Process does not return Path as desired, thus I cannot Where with Path. Is there a way to Get-Process / Stop-Process on remote machine under a specific path?
// Paths are filled
PS C:\> Get-Process | Format-Table Name, Path
Name Path
---- ----
firefox C:\Program Files (x86)\Mozilla Firefox\firefox.exe
// Paths are empty
PS C:\> Get-Process -ComputerName localhost | Format-Table Name, Path
Name Path
---- ----
firefox
You could use Invoke-Command if Remoting is enabled on the remote server, and perform your action in the scriptblock of the command:
Invoke-Command -ComputerName remoteComputer -Script { param($pathFilter) Get-Process | ?{$_.Path -like $pathFilter} | Format-Table Name, Path } -Args "somefilter*"
I had a similar case that I resolved by using x64 version of powershell.