internal/functions/Invoke-ManagedComputerCommand.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
function Invoke-ManagedComputerCommand {
    <#
        .SYNOPSIS
            Runs wmi commands against a target system.
 
        .DESCRIPTION
            Runs wmi commands against a target system.
            Either directly or over PowerShell remoting.
 
        .PARAMETER ComputerName
            The target to run against. Must be resolvable.
 
        .PARAMETER Credential
            Credentials to use when using PowerShell remoting.
 
        .PARAMETER ScriptBlock
            The scriptblock to execute.
            Use $wmi to access the smo wmi object.
            Must not include a param block!
 
        .PARAMETER ArgumentList
            The arguments to pass to your scriptblock.
            Access them within the scriptblock using the automatic variable $args
 
        .PARAMETER EnableException
            Left in for legacy reasons. This command will throw no matter what
       #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [Alias("Server")]
        [dbainstanceparameter]$ComputerName,
        [PSCredential]$Credential,
        [Parameter(Mandatory)]
        [scriptblock]$ScriptBlock,
        [string[]]$ArgumentList,
        [switch][Alias('Silent')]
        $EnableException # Left in for legacy but this command needs to throw
    )

    $computer = $ComputerName.ComputerName

    $null = Test-ElevationRequirement -ComputerName $computer -EnableException $true

    $resolved = Resolve-DbaNetworkName -ComputerName $computer -Turbo
    $ipaddr = $resolved.IpAddress
    $ArgumentList += $ipaddr

    [scriptblock]$setupScriptBlock = {
        $ipaddr = $args[$args.GetUpperBound(0)]

        # Just in case we go remote, ensure the assembly is loaded
        [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SqlWmiManagement')
        $wmi = New-Object Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer $ipaddr
        $null = $wmi.Initialize()
    }

    $prescriptblock = $setupScriptBlock.ToString()
    $postscriptblock = $ScriptBlock.ToString()

    $scriptblock = [ScriptBlock]::Create("$prescriptblock $postscriptblock")
    Write-Message -Level Verbose -Message "Connecting to SQL WMI on $computer."

    try {
        Invoke-Command2 -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList -Credential $Credential -ErrorAction Stop
    } catch {
        Write-Message -Level Verbose -Message "Local connection attempt to $computer failed. Connecting remotely."

        # For surely resolve stuff, and going by default with kerberos, this needs to match FullComputerName
        $hostname = $resolved.FullComputerName

        Invoke-Command2 -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList -ComputerName $hostname -Credential $Credential -ErrorAction Stop
    }
}