Run a local PowerShell Function against a Remote Computer with PowerShell Remoting

Did you know that it's super easy to run a function that exists only on your local computer against a remote computer even when no remoting capabilities have been added to the function itself? It does however require that PowerShell remoting be enabled on the remote system, but if you're running Windows Server 2012 or higher, PowerShell remoting is enabled by default on those operating systems.

I'll start off by creating a function that performs a meaningful task so I can use it to demonstrate this process.

In my last blog article Use PowerShell to Determine the PDC Emulator FSMO Role Holder in your Active Directory Forest Root Domain, I showed you how to determine which domain controller holds the PDC emulator FSMO role in your Active Directory environment’s forest root domain. This is the domain controller that is ultimately responsible for the time in your Active Directory environment and it should be set to synchronize its time from an external time source.

I’ve created a function named Get-ADTimeSyncSetting as shown in the following code example which retrieves several time related settings that I want to see the values for:

 1function Get-ADTimeSyncSetting {
 3    $AnnounceFlags = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\config -Name AnnounceFlags
 4    $MaxNegPhaseCorrection = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config -Name MaxNegPhaseCorrection
 5    $MaxPosPhaseCorrection = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config -Name MaxPosPhaseCorrection
 6    $NtpServer = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters -Name NtpServer
 7    $Type = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters -Name Type
 8    $SpecialPollInterval = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient -Name SpecialPollInterval
 9    $Enabled = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer -Name Enabled
11    [PSCustomObject]@{
12        AnnounceFlags = $AnnounceFlags.AnnounceFlags
13        MaxNegPhaseCorrection = $MaxNegPhaseCorrection.MaxNegPhaseCorrection
14        MaxPosPhaseCorrection = $MaxPosPhaseCorrection.MaxPosPhaseCorrection
15        NtpServer = $NtpServer.NtpServer
16        Type = $Type.Type
17        SpecialPollInterval = $SpecialPollInterval.SpecialPollInterval
18        Enabled = $Enabled.Enabled
19    }

This function has been saved locally in the scripts folder on my Windows 8.1 computer. Since I haven’t added this function to a module yet and it only exists in a ps1 file, I’ll first need to dot source the ps1 file:

1. .\Get-ADTimeSyncSetting.ps1


I can see that the function now exists locally on the function PSDrive on my Windows 8.1 computer:

1Get-ChildItem -Path Function:\Get-ADTimeSyncSetting


It's time for the magic of running this local function from my Windows 8.1 computer against the domain controller named dc01 which holds the PDC eumlator FSMO role in the forest root domain in my Active Directory environment:

1Invoke-Command -ComputerName dc01 ${function:Get-ADTimeSyncSetting}


Based on the previous results, I can see that these are the default settings and they need to be changed in order for this server to synchronize it's time from an external time source. You may think that this machine is synchronizing its time from since that is defined and shown in the previous results, but that's not the case since "NT5DS" is the type which means to synchronize from the PDC emulator in a domain environment as noted in the previously referenced TechNet blog article.

The process of running a local function against a remote computer looks like magic until you dig into what's happening. First, the ScriptBlock positional parameter was omitted in the previous example and is shown here which helps in figuring out what's happening:

1Invoke-Command -ComputerName dc01 -ScriptBlock ${function:Get-ADTimeSyncSetting}


The second piece of information that's needed to demystify this magic is seeing what happens when only running the portion of the command with the reference to Get-ADTimeSyncSetting on the Function PSDrive inside of curly braces with the preceding dollar sign: