Script Center > Gallery > Servers > Common Connect Functions - 14.0.1
TechNet Script Center logo

Welcome to the TechNet Script Center Gallery!

Each contribution is licensed to you under a License Agreement by its owner, not Microsoft. Microsoft does not guarantee the contribution or purport to grant rights to it.

Common Connect Functions - 14.0.1

(Community)
Rate it:
 
 
 
 
 
Script Code
Windows PowerShell
# CommonConnectFunctions.ps1
# Copyright (c) 2010 Microsoft Corporation. All rights reserved. 
# This script contains all the common Powershell functions required to connect to remote PS, both in Enterprise and Datacenter

$CommonFunctionsScriptVersion="14.0.1"

## PROMPT ####################################################################

## PowerShell can support very rich prompts, this simple one prints the current
## working directory and updates the console window title to show the machine 
## name and directory.  

function prompt 
{ 
	$cwd = (get-location).Path
	$host.UI.RawUI.WindowTitle = "Machine: " + $global:connectedFqdn 
	$host.UI.Write("Yellow", $host.UI.RawUI.BackGroundColor, "[PS]")
	" $cwd>" 
}

## generates a tip of the day 

function get-tip
{
    param($local:number=$null) 

    if( ($global:exrandom -eq $null) -or ($exrandom -isnot [System.Random]))
    {
        $global:exrandom = new-object System.Random
    }

    $exchculture = [System.Threading.Thread]::CurrentThread.CurrentUICulture
    $foundculture = $false
    while($exchculture -ne [Globalization.CultureInfo]::InvariantCulture -and !$foundculture)
    {
    	if ( test-path "$($global:exbin)\$($exchculture.Name)\extips.xml" )
    	{
    		$foundculture = $true
    	}
    	else
    	{
    		$exchculture = $exchculture.Parent
    	}
    }

	if($foundculture -eq $true)
    {
	$exchculture = $exchculture.Name 
    }
    else 
    {
	$exchculture = 'en'
    } 

    if (test-path "$($global:exbin)\$exchculture\extips.xml")
    {

        $local:tips = [xml](get-content $global:exbin\$exchculture\extips.xml)
        if($local:number -eq $null)
        {
            $local:temp = $global:exrandom.Next( 0, $local:tips.topic.developerConceptualDocument.introduction.table.row.Count )
        }
        else
        {
            $local:temp = $local:number
        }
        $local:nav = $tips.topic.developerConceptualDocument.introduction.table.row[$local:temp].entry.CreateNavigator()
        write-host -fore Yellow ( "Tip of the day #" + $local:temp + ":`n" )
        [void] $nav.MoveToFirstChild()
        do
        {
             write-host $nav.Value
        }
        while( $nav.MoveToNext() )
        ""
    }
    else
    {
        "Exchange tips file $($global:exbin)\$exchculture\extips.xml not found!"
    }

    trap
    {
	continue
    }
}

function ImportPSSession ([bool]$ClearCache)
{
	if (!($global:remoteSession -eq $null))
	{
	    # do not display all the commands - turn off verbose output
	    set-variable VerbosePreference -value SilentlyContinue

	    $serverName = $global:remoteSession.ComputerName
	    $modulePath = "$env:APPDATA\Microsoft\Exchange\RemotePowerShell\$serverName"
	    $remotePSSettinsPath = "HKCU:Software\Microsoft\ExchangeServer\v14\RemotePowerShell\$serverName"

	    if ($ClearCache)
	    {
	        Write-Host -fore Yellow "Clearing session cache and registry entry..."
	        ClearRegistryEntryAndModule $remotePSSettinsPath $modulePath
	    }
	    
	    try
	    {
	    	ExportPSSessionAndImportModule $remotePSSettinsPath $modulePath
	    }
	    catch
	    {
	        Write-Warning "Cannot generate Export-Module for the current session, using Import-PSession."
	    }
	    $global:importResults = Get-Module
	    if ($global:importResults -eq $null)
	    {
	        $global:importResults=Import-PSSession $global:remoteSession -WarningAction SilentlyContinue -DisableNameChecking
	    }

	    set-variable VerbosePreference -value Continue

	    Write-Verbose "Connected to $global:connectedFqdn."
	}
}


function ExportPSSessionAndImportModule ($remotePSSettinsPath, $modulePath)
{
	$hashValue = $global:remoteSession.ApplicationPrivateData.ImplicitRemoting.Hash
	$CurrentUserRemotePSSettings = Get-ItemProperty -path $remotePSSettinsPath -ErrorAction SilentlyContinue

	if (($CurrentUserRemotePSSettings -eq $null) -or ($CurrentUserRemotePSSettings.Hash -eq $null) -or (-not ($CurrentUserRemotePSSettings.ModulePath)) -or ($CurrentUserRemotePSSettings.Hash -ne $hashValue))
	{
		# Redo Everything, when:
		# 1. No registry entry found, or
		# 2. Registry entry exists, but hash value or ModulePath is empty (which is very unlikely) or
		# 3. Hash value of the saved module didn't match with the hash value of the current session
		CreateRegistryEntryAndImportModule $remotePSSettinsPath $hashValue $modulePath
	}
	else
	{
		$modulePath = $CurrentUserRemotePSSettings.ModulePath
		$module =  Get-ChildItem $modulePath -ErrorAction SilentlyContinue | where-object{$_.Extension -eq ".psm1" -or $_.Extension -eq ".psd1" -or $_.Extension -eq ".ps1xml"}
		if (($module -eq $null) -or ($module.Count -lt 3))
		{
			# If the module folder exists, but any module file is missing, then we should just export the session and import module
			Export-PSSession -Session $global:remoteSession -OutputModule $modulePath -force | out-null
			Import-Module -Name $modulePath -ArgumentList $global:remoteSession -DisableNameChecking
		}
		else
		{
			if  ((New-TimeSpan -Start $module[0].LastWriteTime -End (get-date)).TotalHours -gt 72)
			{
				# If the module is expired, then we should redo everything
				CreateRegistryEntryAndImportModule $remotePSSettinsPath $hashValue $modulePath
			}
			else
			{
				Import-Module -Name $modulePath -ArgumentList $global:remoteSession -DisableNameChecking
			}
		}
	}
}

function CreateRegistryEntryAndImportModule ($remotePSSettinsPath, $hashValue, $modulePath )
{
	ClearRegistryEntryAndModule $remotePSSettinsPath $modulePath
	new-item $remotePSSettinsPath -force | out-null
	New-ItemProperty -Path $remotePSSettinsPath -Name Hash -Value $hashValue -PropertyType DWord -force | out-null
	New-ItemProperty -Path $remotePSSettinsPath -Name ModulePath -value $modulePath -PropertyType ExpandString -force | out-null
	Export-PSSession -Session $global:remoteSession -OutputModule $modulePath -force | out-null
	Import-Module -Name $modulePath -ArgumentList $global:remoteSession -DisableNameChecking
}

function ClearRegistryEntryAndModule ($remotePSSettinsPath, $modulePath)
{
	clear-item $remotePSSettinsPath -force -ErrorAction SilentlyContinue
	Get-ChildItem $modulePath -ErrorAction SilentlyContinue | Remove-Item -force -recurse -ErrorAction SilentlyContinue
}

##########################################################################################################################
#
#  Contains cmdlets which create a PSCredential object by consuming user
#  input in the form of a liveID (like user@hotmail.com) and password.
#
#  This module depends on SSPIPromptForCredentials win32 API for generating Nego2/LiveSSP token
#  PSHostUserInterface method PromptForCredential will not work for Nego2
#
  
######### PInvoke code which retrieves PSCredential using SSPIPromptForCredentials #########
$getLiveIDCredCode = @"
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace Microsoft.PowerShell.Commands
{
    [StructLayout(LayoutKind.Sequential)]
    public struct CREDUI_INFO
    {
        public int cbSize;
        public IntPtr hwndParent;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pszMessageText;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pszCaptionText;
        public IntPtr hbmBanner;
    }

    public class LiveIDCredential
    {
        private const string NEGOSSP_NAME_W = "Negotiate";
        private const string NEGOSSP_2_W = "Nego2";

        public static PSCredential GetLiveIDCredential(string captionText,
            string messageText,
            string connectionUri)
        {
            // This will throw if the connectionUri is not a valid uri string.
            Uri connUri = new UriBuilder(connectionUri).Uri;
            WSManConnectionInfo cInfo = new WSManConnectionInfo(
                connUri, (string)null, (System.Management.Automation.PSCredential)null);
            cInfo.AuthenticationMechanism = AuthenticationMechanism.Negotiate;
            Runspace remoteRunspace = RunspaceFactory.CreateRunspace(cInfo);
            try
            {
                remoteRunspace.Open();
            }
            catch (Exception)
            {
            }

            CREDUI_INFO credUiInfo = new CREDUI_INFO();
            credUiInfo.pszCaptionText = captionText;
            credUiInfo.pszMessageText = messageText;
            credUiInfo.hwndParent = IntPtr.Zero;
            credUiInfo.hbmBanner = IntPtr.Zero;
            credUiInfo.cbSize = Marshal.SizeOf(credUiInfo);

            IntPtr ppAuthIdentity = IntPtr.Zero;
            bool fSave = false;

            string targetName = connUri.Host;
            int result = SspiPromptForCredentials(targetName,
                ref credUiInfo,
                0,
                NEGOSSP_NAME_W,
                IntPtr.Zero,
                ref ppAuthIdentity,
                ref fSave,
                1);

            if (0 != result)
            {
                throw new System.InvalidOperationException(
                    string.Format(CultureInfo.InvariantCulture,
                    "SspiPromptForCredentials failed with error {0}", result));
            }


            StringBuilder pszUserName = new StringBuilder();
            StringBuilder pszDomainName = new StringBuilder();
            StringBuilder pszPassword = new StringBuilder();

            result = SspiEncodeAuthIdentityAsStrings(ppAuthIdentity,
                ref pszUserName,
                ref pszDomainName,
                ref pszPassword);

            if (0 != result)
            {
                throw new System.InvalidOperationException(
                    string.Format(CultureInfo.InvariantCulture,
                    "SspiEncodeAuthIdentityAsStrings failed with error {0}", result));
            }

            System.Security.SecureString pwd = new System.Security.SecureString();
            for (int i = 0; i < pszPassword.Length; i++)
            {
                pwd.AppendChar(pszPassword[i]);
            }

            string userName = null;
            if (pszDomainName != null)
            {
                userName = string.Format(CultureInfo.InvariantCulture,
                    "{0}\\{1}", pszDomainName.ToString(), pszUserName.ToString());
            }
            else
            {
                userName = pszUserName.ToString();
            }

            PSCredential credToReturn = new PSCredential(userName, pwd);
            return credToReturn;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pszTargetName">
        /// A pointer to a null-terminated string that indicates the 
        /// service principal name (SPN) or the security context of the 
        /// destination server.
        /// </param>
        /// <param name="pUiInfo">
        /// A pointer to a CREDUI_INFO structure that contains information 
        /// for customizing the appearance of the dialog box.
        /// </param>
        /// <param name="dwAuthError">
        /// A Windows error code, defined in WinError.h, that is displayed in the dialog box.
        /// If credentials previously collected were not valid, the caller uses this parameter
        /// to pass the error message from the API that collected the credentials (for example, Winlogon)
        /// to this function. The corresponding error message is formatted and displayed in the dialog box.
        /// Set the value of this parameter to zero to display no error message.
        /// </param>
        /// <param name="pszPackage">
        /// contains the name of authentication package
        /// </param>
        /// <param name="pInputAuthIdentity"></param>
        /// <param name="ppAuthIdentity"></param>
        /// <param name="pfSave">
        /// A pointer to a Boolean value that, on input, specifies whether the Save check box is 
        /// selected in the dialog box that this function displays. On output, the value of this 
        /// parameter specifies whether the Save check box was selected when the user clicks the
        /// Submit button in the dialog box. Set this parameter to NULL to ignore the Save check box.
        /// 
        /// This parameter is ignored if the CREDUIWIN_CHECKBOX flag is not set in the dwFlags parameter.
        /// </param>
        /// <param name="dwFlags">
        /// 1. SSPIPFC_CHECKBOX  0x1 -- If applications need to show the 
        /// checkbox to save credentials, the SSPIPFC_CHECKBOX should be set.
        /// 2. SSPIPRFC_SAVE_CRED_BY_CALLER 0x2 
        /// By default, the credential provier() saves the credentials to Credman/KeyRing 
        /// with CRED_PERSIST_ENTERPRISE persistence(http://msdn2.microsoft.com/en-us/library/aa374788(VS.85).aspx),
        /// but the caller can overrides this behavior by supplying SSPIPFC_SAVE_CRED_BY_CALLER.
        /// When this flag is set, the credential provider does not save the credentials to credman/keyring. 
        /// </param>
        /// <returns></returns>
        [DllImport("credui", SetLastError = false, CharSet = CharSet.Unicode)]
        private static extern int SspiPromptForCredentials(
            string pszTargetName,
            ref CREDUI_INFO pUiInfo,
            int dwAuthError,
            string pszPackage,
            IntPtr pInputAuthIdentity,
            ref IntPtr ppAuthIdentity,
            ref bool pfSave,
            int dwFlags);

        [DllImport("sspicli", SetLastError = false, CharSet = CharSet.Unicode)]
        private static extern int SspiEncodeAuthIdentityAsStrings(
            IntPtr pAuthIdentity,
            ref StringBuilder pszUserName,
            ref StringBuilder pszDomainName,
            ref StringBuilder pszPackedCredentialsString);
    }
}
"@

######### END: PInvoke #####################################################################

function EnsureLiveIDCredentialTypeIsLoaded
{
    if (!('Microsoft.PowerShell.Commands.GetLiveIDCredential' -as [type]))
    {
        # LiveIDCredential Type is not loaded. So load it using Add-Type
        try
        {
			add-type -TypeDefinition $getLiveIDCredCode
		}
		catch
		{
			# We can ignore any TYPE_ALREADY_EXISTS exception
			if ($error[0].FullyQualifiedErrorId -notmatch "TYPE_ALREADY_EXISTS")
			{
				throw
			}
		}
    }
}

function Get-ExLiveIDCredential
{
   [CmdletBinding()]
   param(
     [Parameter(Position=0)]
     [string]$connectionUri
   )
   
   begin
   {
        EnsureLiveIDCredentialTypeIsLoaded
        $captionText = "LiveID Credential";
        $messageText = "Supply credentials for connecting to {0}" -f $connectionUri
        [Microsoft.PowerShell.Commands.LiveIDCredential]::GetLiveIDCredential($captionText,$messageText,$connectionUri)           
   }
}
##########################################################################################################################
# CommonConnectFunctions.ps1
Platforms
Windows Server 2008 R2 Yes
Windows Server 2008 Yes
Windows Server 2003 No
Windows 7 Yes
Windows Vista Yes
Windows XP No
Windows 2000 No
For online peer support, join The Official Scripting Guys Forum! To provide feedback or report bugs in sample scripts, please start a new discussion on the Discussions tab for this script.
Disclaimer The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
Be the first to create a discussion.