Remotely connecting to domain controller to use AD module

Hi all,

If I want to write a script where I do not assume that the local PC has RSAT tools installed in order to get the AD module and also I am not assuming the user is launching PowerShell with their admin credentials.

How do I remotely connect to a domain controller in order to launch AD commands and at the end of my script terminate the remote connection?

With Exchange it looks a bit like:

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url -Credential $UserCredential
Import-PSSession $Session -AllowClobber -DisableNameChecking

Pretty similar to Exchange the only difference is out of the box there is no configuration name configured for active directory so you will have to manually load the module before importing the session.

$session = New-PSSession -ComputerName DC -Credential (Get-Credential)
Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
Import-PSSession -Session $session
Get-ADUser Administrator
Get-PSSession | Remove-PSSession

Hi Anthony,

that makes sense. So one final question. Obviously i cant stop someone from launching PowerShell as their admin account and perhaps they do indeed have RSAT tools installed.

So i read earlier another way that you can connect to a remove domain controller and then export commands out so instead of running Get-ADComputer it becomes Get-REMADComputer

I want my script / function to behave the same in all circumstances. not sure if that makes a difference as so which option i use?

Update: this was the link i found: https://technet.microsoft.com/en-us/magazine/ff720181.aspx

Found this which is the same as what you are doing but with the -prefix :slight_smile:

http://theitjesus.com/powershell-remote-session-to-domain-controller/

At least i know if using Get-REMUser then it is from that session :slight_smile:

You can add the prefix if you want, but do you want it? Naturally you’d want your script to work the same no matter the environment so I would try to keep using the same cmdlets no matter what. At which point I would try to work in a check on the local machine where the session is being executed from and see if the local machine has the AD module available and if it does just do it locally but if it doesn’t open a remote session to a machine that does have it available. Something like this:

if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {
  Import-Module ActiveDirectory
  Get-ADUser Administrator
}
else {
  $session = New-PSSession -ComputerName DC -Credential (Get-Credential)
  Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
  Import-PSSession -Session $session
  Get-ADUser Administrator
}

The thing I would try to avoid is if you use the replacement cmdlet you created (REMUser) for long enough you are going to get used to that cmdlet and probably forget what the original is at some point then scratch your head later on if it ever stops working. Because I could see that happening in my environment with some less PowerShell savvy individuals :stuck_out_tongue:

Hi Anthony,

thank you for that, I guess you are correct. Will look into how i can pass credentials with AD commands just in case someone open a PS console locally that has the ActiveDirectory module. Obviously a non admin account cant do New-ADUser :wink:

@Ronnie Jorgensen, as a side note:

“Obviously i cant stop someone from launching PowerShell as their admin account”

You can.
You should.
As should everyone that holds a security conscience mind.
Especially after upgrading to WMF 5.0.

PowerShell Jea - Just Enough Administration.

https://msdn.microsoft.com/en-us/powershell/jea/using-jea
https://msdn.microsoft.com/en-us/library/dn896648.aspx

@Anthony, hoping you can help again.

I tried to make your code above into a function in a module bur seems it is not working so great.

function Connect-ARWActiveDirectory {

    [CmdLetBinding()]
    Param(
        [Parameter(
            Mandatory=$true
        )]
        [string]$ConnectTo = "Server.FQDN"
    )

    if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {
        Import-Module ActiveDirectory -Global
    }
    else {
        $session = New-PSSession -ComputerName $ConnectTo -Credential (Get-Credential)
        Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
        Import-PSSession $Session
    }

}

It gives error:
Import-PSSession : Running the Get-Command command in a remote session reported the following error: Processing data
for a remote command failed with the following error message: For more information, see the
about_Remote_Troubleshooting Help topic…
At C:\home\Posh\Modules\ArrowADTools\ArrowADTools.psm1:17 char:9

  •     Import-PSSession $Session
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidResult: (:slight_smile: [Import-PSSession], RuntimeException
    • FullyQualifiedErrorId : ErrorFromRemoteCommand,Microsoft.PowerShell.Commands.ImportPSSessionCommand

So tried something that was mentioned to me for the same for Exchange. but still does not seem to work

$session = New-PSSession -ComputerName "FRVCBVDC003P.euecs.corp.arrow.com" -Credential (Get-Credential)
Invoke-Command -session $session -ScriptBlock { Import-Module ActiveDirectory }
Import-Module (Import-PSSession -session $session -Module ActiveDirectory -Prefix ARW -DisableNameChecking -AllowClobber) -Global

Any ideas? the commands are not available after function stops

Using your function it works for me in my lab…

function Connect-ARWActiveDirectory {

    [CmdLetBinding()]
    Param(
        [Parameter(
            Mandatory=$true
        )]
        [string]$ConnectTo = "DC"
    )

    if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {
        Write-Verbose -Message "Importing AD module" -Verbose
        Import-Module ActiveDirectory -Global
    }
    else {
        Write-Verbose -Message "No AD module found starting remote connection" -Verbose
        $session = New-PSSession -ComputerName $ConnectTo -Credential (Get-Credential)
        Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
        Import-PSSession $Session
    }

}

It imports the remote session

ModuleType Version    Name                                ExportedCommands                                                                                                                                                                                                                                          
---------- -------    ----                                ----------------                                                                                                                                                                                                                                          
Script     1.0        tmp_0mj4z1lk.lfe                    {Add-ADCentralAccessPolicyMember, Add-ADComputerServiceAccount, Add-ADDomainControllerPasswordReplicationPolicy, Add-ADFineGrainedPasswordPolicySubject...}

Get-ADUser returns the source as the imported session

PS C:\Users\Administrator.HOME> get-command Get-ADUser

CommandType     Name                                               Version    Source                                                                                                                                                                                                                                
-----------     ----                                               -------    ------                                                                                                                                                                                                                                
Function        Get-ADUser                                         1.0        tmp_llxkgus4.0lf

The error to me doesn’t look like it’s a problem with the code but more so a problem with permissions remoting?

Check what permissions are set for remote powershell sessions by doing this:

PS C:\Windows\system32> Get-PSSessionConfiguration |fl 


Name          : microsoft.powershell
PSVersion     : 4.0
StartupScript : 
RunAsUser     : 
Permission    : BUILTIN\Administrators AccessAllowed, BUILTIN\Remote 
                Management Users AccessAllowed

Name          : microsoft.powershell.workflow
PSVersion     : 4.0
StartupScript : 
RunAsUser     : 
Permission    : BUILTIN\Administrators AccessAllowed, BUILTIN\Remote 
                Management Users AccessAllowed

Name          : microsoft.powershell32
PSVersion     : 4.0
StartupScript : 
RunAsUser     : 
Permission    : BUILTIN\Administrators AccessAllowed, BUILTIN\Remote 
                Management Users AccessAllowed

Name          : microsoft.windows.servermanagerworkflows
PSVersion     : 3.0
StartupScript : 
RunAsUser     : 
Permission    : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators 
                AccessAllowed

If the account you are using isn’t in one of those groups you may need to give it permissions using

Set-PSSessionConfiguration -Name Microsoft.PowerShell -showSecurityDescriptorUI

@Anthony - Are you running this from a custom module? I have a module “ArrowADTools.psm1” that is imported in my PowerShell profile. so if i run Connect-ARWActiveDirectory it will connect and run but once done running i have no access to Get-ADUser

It technically shouldn’t matter if it’s a function or a module in this particular case but either way to be sure I created it as a module in

C:\Program Files\WindowsPowerShell\Modules</pre> called ARWActiveDirectory

PS C:\Users\Administrator.HOME> Get-Module

ModuleType Version    Name                                ExportedCommands                                                                                                                                                                                                                                          
---------- -------    ----                                ----------------                                                                                                                                                                                                                                          
Script     0.0        ARWActiveDirectory                  Connect-ARWActiveDirectory                                                                                                                                                                                                                                
Script     1.0.0.0    ISE                                 {Get-IseSnippet, Import-IseSnippet, New-IseSnippet}                                                                                                                                                                                                       
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}                                                                                                                                                                                        
Manifest   3.0.0.0    Microsoft.PowerShell.Security       {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl, Get-AuthenticodeSignature...}                                                                                                                                                                 
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...} 

The script module has the following contents

function Connect-ARWActiveDirectory {

    [CmdLetBinding()]
    Param(
        [Parameter(
            Mandatory=$true
        )]
        [string]$ConnectTo = "DC"
    )

    if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {
        Write-Verbose -Message "Importing AD module" -Verbose
        Import-Module ActiveDirectory -Global
    }
    else {
        Write-Verbose -Message "No AD module found starting remote connection" -Verbose
        $session = New-PSSession -ComputerName $ConnectTo -Credential (Get-Credential)
        Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
        Import-PSSession $Session -Module ActiveDirectory
    }

}

Once I run Connect-ARWActiveDirectory I connected with both an admin user and a normal user given specific permissions as mentioned above and I get the following

PS C:\Users\Administrator.HOME> Connect-ARWActiveDirectory
cmdlet Connect-ARWActiveDirectory at command pipeline position 1
Supply values for the following parameters:
ConnectTo: DC
VERBOSE: No AD module found starting remote connection
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:

ModuleType Version    Name                                ExportedCommands                                                                                                                                                                                                                                          
---------- -------    ----                                ----------------                                                                                                                                                                                                                                          
Script     1.0        tmp_3vd0hdc1.2za                    {Add-ADCentralAccessPolicyMember, Add-ADComputerServiceAccount, Add-ADDomainControllerPasswordReplicationPolicy, Add-ADFineGrainedPasswordPolicySubject...} 

@Anthony,

Ok so my domain controllers had PS 2.0 so i updated to OS 5.0 and now it work. however i get some errors but not sure if thats because i already have AD module on local machine?

Import-PSSession : Proxy creation has been skipped for the ‘%’ command, because Windows PowerShell could not verify
the safety of the command name.
At C:\home\Posh\Modules\ArrowADTools\ArrowADTools.psm1:19 char:9

  •     Import-PSSession $Session
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : InvalidData: (:slight_smile: [Import-PSSession], InvalidOperationException
    • FullyQualifiedErrorId : ErrorSkippedUnsafeCommandName,Microsoft.PowerShell.Commands.ImportPSSessionCommand

and then this error:

WARNING: Proxy creation has been skipped for the following command: ‘ac, asnp, cat, cd, CFS, chdir, clc, clear, clhy,
cli, clp, cls, clv, cnsn, compare, copy, cp, cpi, cpp, curl, cvpa, dbp, del, diff, dir, dnsn, ebp, echo, epal, epcsv,
epsn, erase, etsn, exsn, fc, fhx, fl, foreach, ft, fw, gal, gbp, gc, gci, gcm, gcs, gdr, ghy, gi, gjb, gl, gm, gmo, gp,
gps, gpv, group, gsn, gsnp, gsv, gu, gv, gwmi, h, history, icm, iex, ihy, ii, ipal, ipcsv, ipmo, ipsn, irm, ise, iwmi,
iwr, kill, lp, ls, man, md, measure, mi, mount, move, mp, mv, nal, ndr, ni, nmo, npssc, nsn, nv, ogv, oh, popd, ps,
pushd, pwd, r, rbp, rcjb, rcsn, rd, rdr, ren, ri, rjb, rm, rmdir, rmo, rni, rnp, rp, rsn, rsnp, rujb, rv, rvpa, rwmi,
sajb, sal, saps, sasv, sbp, sc, select, set, shcm, si, sl, sleep, sls, sort, sp, spjb, spps, spsv, start, sujb, sv,
swmi, tee, trcm, type, wget, where, wjb, write, A:, B:, C:, cd…, cd, Clear-Host, ConvertFrom-SddlString, D:, E:, F:,
Format-Hex, G:, Get-FileHash, Get-Verb, H:, help, I:, Import-PowerShellDataFile, ImportSystemModules, J:, K:, L:, M:,
mkdir, more, N:, New-Guid, New-TemporaryFile, O:, oss, P:, Pause, prompt, Q:, R:, S:, T:, TabExpansion2, U:, V:, W:,
X:, Y:, Z:, Add-History, Add-Member, Add-PSSnapin, Add-Type, Clear-History, Clear-Variable, Compare-Object,
Connect-PSSession, ConvertFrom-Csv, ConvertFrom-Json, ConvertFrom-String, ConvertFrom-StringData, Convert-String,
ConvertTo-Csv, ConvertTo-Html, ConvertTo-Json, ConvertTo-Xml, Debug-Job, Debug-Runspace, Disable-PSBreakpoint,
Disable-PSRemoting, Disable-PSSessionConfiguration, Disable-RunspaceDebug, Disconnect-PSSession, Enable-PSBreakpoint,
Enable-PSRemoting, Enable-PSSessionConfiguration, Enable-RunspaceDebug, Enter-PSHostProcess, Enter-PSSession,
Exit-PSHostProcess, Export-Alias, Export-Clixml, Export-Console, Export-Csv, Export-FormatData, Export-ModuleMember,
Export-PSSession, ForEach-Object, Format-Custom, Format-List, Format-Table, Format-Wide, Get-Alias, Get-Culture,
Get-Date, Get-Event, Get-EventSubscriber, Get-History, Get-Host, Get-Job, Get-Member, Get-Module, Get-PSBreakpoint,
Get-PSCallStack, Get-PSHostProcessInfo, Get-PSSession, Get-PSSessionCapability, Get-PSSessionConfiguration,
Get-PSSnapin, Get-Random, Get-Runspace, Get-RunspaceDebug, Get-TraceSource, Get-TypeData, Get-UICulture, Get-Unique,
Get-Variable, Group-Object, Import-Alias, Import-Clixml, Import-Csv, Import-LocalizedData, Import-Module,
Import-PSSession, Invoke-Command, Invoke-Expression, Invoke-History, Invoke-RestMethod, Invoke-WebRequest,
Measure-Command, New-Alias, New-Event, New-Module, New-ModuleManifest, New-Object, New-PSRoleCapabilityFile,
New-PSSession, New-PSSessionConfigurationFile, New-PSSessionOption, New-PSTransportOption, New-TimeSpan, New-Variable,
Out-File, Out-GridView, Out-Host, Out-Null, Out-Printer, Out-String, Read-Host, Receive-Job, Receive-PSSession,
Register-ArgumentCompleter, Register-EngineEvent, Register-ObjectEvent, Register-PSSessionConfiguration, Remove-Event,
Remove-Job, Remove-Module, Remove-PSBreakpoint, Remove-PSSession, Remove-PSSnapin, Remove-TypeData, Remove-Variable,
Resume-Job, Save-Help, Select-String, Select-Xml, Send-MailMessage, Set-Alias, Set-Date, Set-PSBreakpoint, Set-PSDebug,
Set-PSSessionConfiguration, Set-StrictMode, Set-TraceSource, Set-Variable, Show-Command, Sort-Object, Start-Job,
Start-Sleep, Stop-Job, Suspend-Job, Tee-Object, Test-ModuleManifest, Test-PSSessionConfigurationFile, Trace-Command,
Unblock-File, Unregister-Event, Unregister-PSSessionConfiguration, Update-FormatData, Update-Help, Update-List,
Update-TypeData, Wait-Debugger, Wait-Event, Wait-Job, Where-Object, Write-Debug, Write-Error, Write-Host,
Write-Information, Write-Output, Write-Progress, Write-Verbose, Write-Warning’, because it would shadow an existing
local command. Use the AllowClobber parameter if you want to shadow existing local commands.

ModuleType Version Name ExportedCommands


Script 1.0 tmp_1iaye12n.tvb {Add-ADComputerServiceAccount, Add-ADDomainControllerPassw…

Just add -Module ActiveDirectory to the end of import-session. It’s trying to import all the commands from the domain controller that are loaded by default which as you can see is a lot of pointless ones that you generally should have locally already anyway.

Hi anthony,

Done that and it looks better, however it is still not working for me… the commands are “gone”

Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS C:\home\Posh> Connect-ARWActiveDirectory
VERBOSE: No AD module found starting remote connection

cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
VERBOSE: Invoke Command
VERBOSE: Import pssession

ModuleType Version Name ExportedCommands


Script 1.0 tmp_gcgle5oh.1g4 {Add-ADComputerServiceAccount, Add-ADDomainControllerPassw…

PS C:\home\Posh> get-command Get-ADUser

CommandType Name Version Source


Cmdlet Get-ADUser 1.0.0.0 ActiveDirectory

PS C:\home\Posh>

Cool, I could replicate that on my end… really odd looks like a scoping issue. Few changes and the below is working on my end

function Connect-ARWActiveDirectory {

    [CmdLetBinding()]
    Param(
        [Parameter(
            Mandatory=$true
        )]
        [string]$ConnectTo = "DC"
    )

    if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {
        Write-Verbose -Message "Importing AD module" -Verbose
        Import-Module ActiveDirectory -Global
    }
    else {
        Write-Verbose -Message "No AD module found starting remote connection" -Verbose
        $session = New-PSSession -ComputerName $ConnectTo -Credential (Get-Credential)
        Import-Module -PSSession $session -Name ActiveDirectory -Global
    }
}

Hi Anthony,

Will be checking this out now but i want to quickly ask you something. In the line:
if ((Get-Module ActiveDirectory -ErrorAction silentlycontinue)) {

Should that not really be with the -ListAvailable ?? Get-Module ActiveDirectory is sort of already loaded and active?

Also i have been thinking. if my goal is to have a consistent experience regardless of locally RSAT is installed or not. is it not just a matter of i skip that IF ELSE block and just connect to AD?

Import-Module ActiveDirectory in the IF block is ok but lets say like on my normal laptop i just open PowerShell console as administrator but not run as my domain admin. i get the AD commands but i will have access denied if i tried new-aduser for example

Hmm not working from me, but could be because i am at home on client vpn

Import-Module : Failed to generate proxies for remote module ‘ActiveDirectory’. Could not find a part of the path ‘C:
Users\a47941\AppData\Local\Temp\remoteIpMoProxy_ActiveDirectory_1.0.0.0_FRVCBVDC003Peuecscorparrowcom_d781a3aa-e538-467
d-86f1-9e052a31165e\remoteIpMoProxy_ActiveDirectory_1.0.0.0_FRVCBVDC003Peuecscorparrowcom_d781a3aa-e538-467d-86f1-9e052
a31165e.format.ps1xml’.
At C:\home\Posh\Modules\ArrowADTools\ArrowADTools.psm1:43 char:9

  •     Import-Module -PSSession $session -Name ActiveDirectory -Glob ...
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Import-Module], InvalidOperationException
    • FullyQualifiedErrorId : CmdletProviderInvocationException,Microsoft.PowerShell.Commands.ImportModuleCommand

Yep it should definitely be Get-Module ActiveDirectory -listavailable

You can totally do it that way if you want, just connect directly to the machine that has the AD module installed regardless of weather or not RSAT is installed on the local machine. The thing is though realistically not everyone has permissions to create implicit remote connections to other machines but if you have it installed locally then it’s not a big deal, it all comes down to what permissions you’ve been delegated in AD. At the end of the day no matter which way you go the result is the same.

I can’t really replicate your new problem at the moment. Any testing I’m doing is from a pretty clean lab as I have a bit of time off before I start a new job which means at the moment I don’t have access to a corporate environment with the nuances that come with it.

Hi Anthony,

I need to remote login to get data from Active directory using python. Script is ok but powershell command is not working. I am not expert in powershell. so i need help from you. Please find my below scripts for your reference. Kindly provide exact powershell command to retrieve data from AD.

Python Script:

#!/opt/bin/python2.7
import winrm
import requests
import settings

serv_ip = “My IP”
serv_user = “My UserName”
pwd = “My Password”

ps = “”" $session = New-PSSession -ComputerName wiin2k12-ex1 -Credential (Get-Credential)
Invoke-Command $session -Scriptblock { Import-Module ActiveDirectory }
Import-PSSession -Session $session
Get-ADUser Administrator “”"

def ad_info():

try:
winrmsession = winrm.Session(‘%s’%serv_ip,auth=(‘%s’%serv_user,‘%s’%pwd),transport = ‘ntlm’,server_cert_validation=‘ignore’)
output = winrmsession.run_ps(ps)
print output.std_out
except (requests.exceptions.ConnectionError,winrm.exceptions.InvalidCredentialsError),e:
print e

if name == “main”:

ad_info()

Thanks,
Gopal.