PowerShell 2.0: Accessing Windows Shares during a Remote Session - powershell

I am having trouble accessing a shared network location while within a PowerShell remote session.
From the PowerShell prompt, I enter a new session:
Enter-PSSession server1
The session is properly created and entered. I then attempt to list the contents of the share:
dir \\server2\share1
The response is this error:
Get-ChildItem : Cannot find path '\\server2\share1' because it does not exist.
However, if I remote desktop into server1, bring up PowerShell, and execute the very same dir command, the contents are correctly listed.
I've tried various things using credentials, but that doesn't seem to fix it. I've also confirmed via the "whoami" command that I have the same identity in both examples.
What would cause this?

If you can't use credential delegation as mentioned above, you can mount (or just authenticate as below) the remote share in the remote session using explicit credentials, e.g.
[server1] ps> net use \\server2\share * /user:username
(prompts for password)
[server1] ps> dir \\server2\share
(listing)
This problem has nothing to do with powershell per-se; you are trying to replay your local credentials in a remote session to a third location and falling foul of the NTLM "double hop" limitation.

Read the section "Credential Delegation"
Here - Credit to Keith Hill
and perform the steps if you have not already done so.

Another option is kerberos resource delegation
eg:
$server_name = "my-server" $servers = #(get-adcomputer -identity $server_name)
$target = "target-server" $tgt_srv = get-adcomputer -identity $target
Set-ADComputer -Identity $to_delegate -PrincipalsAllowedToDelegateToAccount $servers

Related

Powershell invoke-command multihopping

I have a question regarding multihopping in a windows environment.
Let's say I have a schedule running on Server A (Central Scheduler) which executes a command on Server B. This script contains a call to save files on a remote filer (UNC path, Server C). Hop 1 (from A to B) works well, hop 2 (from B to C) fails.
I already tested to save the files locally on server B, that works flawlessly.
I think there's a problem with the second hop. I remember reading something like this on a forum a while ago, but can't remember a solution.
In detail, the command looks like this:
$session = New-PSSession -computer ComputerName
$templatepath = "\\filerpath\"
Invoke-Command -Session $session -Scriptblock { powershell ovpmutil cfg pol dnl $Using:templatepath /p \BSH }
To clarify: Powershell gives me an "Access denied" when performing the second hop. I already enabled Credential delegation as described here:
Enabling Multihop Remoting
Any help is appreciated. Thanks in advance
The solution is a real pain in the backside if you ask me but here it is...
On the originating server (A):
Set-Item WSMAN:\localhost\client\auth\credssp -value $true
On the intermediate server (B):
Set-Item WSMAN:\localhost\client\auth\credssp -value $true
Open Group Policy editor on server A, navigate to:
Computer Configuration > Administrative Templates > System > Credentials Delegation
Enable these options:
Allow delegating fresh credentials
Allow delegating fresh credentials with NTLM-only server authentication
Both policies need to have server B added to the allowed list, wildcards are allowed. Note that if you use RDP from server A you'll also need to add TERMSRV/*
When running Invoke-Command from server A, include the -Authentication CredSSP param.
Note that if saving SecureStrings somewhere for the credential to connect to server C, you'll want to either use a fixed encryption (specify byte array) or plain text and convert it.

Powershell "screen" - keep the processes running even the connection is dropped?

I'm using enter-pssession to run scripts on remote servers. So I can login remotely to the servers. Run commands interactively, close the powershell console and later I can reattach the session and check the commands outputs.
Is there a Linux screen like functionality in powershell? I cannot use Windows remote desktop to connect the servers.
You can use Invoke-Command with -InDisconnectedSession, it will start session in asynchronous mode. After you can connect to this session, take data from it, etc. You can read more about this here.
You can create session, disconnect from session, connect back to it.
May be useful for you: New-PSSessionOption with -IdleTimeout.
-IdleTimeout:
Determines how long the session stays open if the remote computer does not receive any communication from the local computer. This includes the heartbeat signal. When the interval expires, the session closes. MSDN Link
I have recently run into double-hop issues with using PSSessions. What I did to work around that is to create a Session Configuration on the remote server that uses the -RunAs parameter to set the credentials that I need the commands on the remote server to be executed as. Then you connect to that session configuration on the remote server, and things should work as expected.
$MyCreds = Get-Credential ''
Invoke-Command -ScriptBlock {
Set-PSSessionConfiguration -Name "My Remote Config" -RunAsCredential $using:MyCreds -Force
} -ComputerName Server01
Then once the session configuration exists I can start a session using that config, and the whole double hop issue is null and void.
Now, mind you I do add some additional security, so that other people cannot use my session config, since that config has my credentials cached on the server (encrypted), and if they used that config they could do whatever they wanted as me. So to accomplish that I get my domain account SID, generate a SDDL line, and restrict access to the Session Config to only my account.
$Searcher = [adsisearcher]"(&(sAMAccountName=$($Creds.UserName.Split('\')[1]))(objectClass=user))"
$Results=$Searcher.FindOne().GetDirectoryEntry()
$MySID = new-object System.Security.Principal.SecurityIdentifier($Results.objectSid.value,0)|% value
$SDDL = "O:NSG:BAD:P(A;;GR;;;BA)(A;;GR;;;IU)(A;;GA;;;$MySID)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
$FQDN = $Server.ServerName,$Server.Forest -join '.'
$MySessionName = "DoubleHop-{0}" -f $MyCreds.UserName.Split('\')[1]
Invoke-Command -ScriptBlock {
Register-PSSessionConfiguration -Name $using:MySessionName -RunAsCredential $using:MyCreds -Force -SecurityDescriptorSddl $using:SDDL
} -ComputerName $FQDN -ea 4

How to list folder permissions located on a different server

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.

How to set share permissions on a remote share with Powershell?

I need to set the share permissions of a remote share from a Powershell 4 script. I've looked at this page, specifically the command Grant-SmbShareAccess but that cmdlet sets permissions on local shares, I would love to have seen a -ComputerName parameter but, alas, there isn't one.
I want to do something like: Grant-SmbShareAccess -ComputerName MYREMOTESERVER -Name <share_name> -AccountName <domain_account> -AccessRight Full
Any ideas on how to do this? My remote server could be a Windows Server or a NetApp vFiler.
EDIT
I tried Matt's suggestion of Invoke-Command in the comments against a NetApp vFiler and got this error:
Connecting to remote server MYREMOTESERVER failed with the following error message : The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. Consult the logs and documentation for the WS-Management service running on the destination, most commonly IIS or WinRM. If the destination is the WinRM service, run the following command on the destination to analyze and configure the WinRM service: "winrm quickconfig".
Changing the security of the share in Windows Explorer works fine.
Grant-SmbShareAccess is a CDXML command, which means that it uses CIM. As you've already noticed, it should only work on a Windows system running at least PSv3 (in this case the WMI class used only exists on Windows 8 and Server 2012 or higher).
There may be other ways to do this against a non-Windows server, but I would try the PowerShell Access Control Module:
$SharePath = "\\ServerName\ShareName"
$Principal = <account name here>
# Add permission to $Principal (-Force will suppress the prompt)
Get-SecurityDescriptor -Path $SharePath -ObjectType LMShare |
Add-AccessControlEntry -Principal $Principal -LogicalShareRights FullControl -Apply #-Force
# Verify:
Get-SecurityDescriptor -Path $SharePath -ObjectType LMShare |
Get-AccessControlEntry
I honestly don't know if this will work since I've only tested it against Windows servers and I don't deal with share permissions very often. Try it out, and if it works, I'll take this part out of the answer.
For Windows Server SMB shares, use the -CimSession parameter.
For non-Windows SMB shares, I would not expect the Windows SMB administration cmdlets to work with them.
The Netapp Powershell toolkit will help with this. Once installed you can import the module into your script, and manage your shares. Here is a rough example that connects to a filer, prompts for a sharename, then configures that share with some default permissions:
# Import the Netapp Powershell Module
import-module dataontap
# Connect to the filer
connect-nacontroller *filername*
# Get the sharename
$sharename = Read-Host -Prompt 'Enter the share you want to configure'
# Configure the CIFS Permissions
Set-NaCifsShareAcl $sharename "Authenticated users" -AccessRights "Change"
Set-NaCifsShareAcl $sharename filername\administrators -AccessRights "Full Control"
Set-NaCifsShareAcl $sharename domain\somegroup -AccessRights "Full Control"
Remove-NaCifsShareAcl $sharename everyone

Grabbing system product keys

So I'm trying to use the PS script found at http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97#content to pull Windows product keys from my domain remotely. However, when it hits a host it returns Exception calling “OpenRemoteBaseKey” with “2″ argument(s): “The network path was not found” instead of the product key. It should also be noted that this works locally. After poking around at the internals of the script, it seems like the offending line is
$remoteReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer)
Research (because I'm totally new to PoSH) indicates that this type of error gets thrown when remote registry access isn't working. Trying to hook into the registry on my test target via regedit shows that I need to have Windows Firewall: Allow inbound remote administration exception set to enabled in Group Policy. I set it and then pulled the updated policy down to the same result. What other stuff might be getting in the way of my connection?
I would recommend using PSRemoting over using the remote registry. Assuming this is set up, all you would have to do is:
$computers = #('localhost')#list of computers
#unless you are currently logged in as a domain admin
# you will need to provide credentials
$cred = Get-Credential domain\administrator
Invoke-Command -Credential $cred -ComputerName $computers -ScriptBlock {
function Get-ProductKey{
#from http://gallery.technet.microsoft.com/scriptcenter/Get-product-keys-of-local-83b4ce97
}
get-ProductKey
}| ft Computername,OSDescription,OSVersion,ProductKey
This will print out the following output:
Computername OSDescription OSVersion ProductKey
------------ ------------- --------- ----------
%name% Microsoft Windows 8 Pro 6.2.9200 XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
I used the following command through powershell, ran it as admin:
wmic /user:jc1_admin /node:pc00202 os get "SerialNumber"