Scem.Support.psm1

<#
.Synopsis
   Short description
.DESCRIPTION
   Long description
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
#>

function Export-SCVMMInfo {
    [CmdletBinding()]
    Param(
        [parameter(Mandatory = $false,
                   Position=0)]
        [string]
        $ComputerName = $env:COMPUTERNAME
        )
    if($null -eq (Get-Module virtualmachinemanager)){
        try{
            Import-Module virtualmachinemanager -ErrorAction Stop
        }
        catch [FileNotFoundException]{
            Write-Error "This does not appear to be a System Center Virtual Machine Manager."
        }
    }

    # Get our VMM Server
    [Microsoft.SystemCenter.VirtualMachineManager.Remoting.ServerConnection]$vmmServer = $null
    $vmmServer = virtualmachinemanager\Get-SCVMMServer -ComputerName $ComputerName

    # Get the .NET Framework Version & add a property
    $dotNetFrameworkVersion = Get-DotNetFrameworkVersion -ComputerName $vmmServer.FQDN
    $vmmServer | Add-Member -NotePropertyName DotNetFrameworkVersion -NotePropertyValue $dotNetFrameworkVersion

    # Write the json to a file
    $vmmServer | ConvertTo-Json | Out-File .\vmmServer.json

    # Get VMM Host Groups & write json
    $vmmHostGroups = Get-SCVMHostGroup -VMMServer $vmmServer
    $vmmHostGroups | ConvertTo-Json | Out-File .\vmmHostGroups.json

    $vmmHostCollection = Get-SCVMHost -VMMServer $vmmServer
    $vmmHostCollection | ConvertTo-Json | Out-File .\vmmHosts.json

    if ($null -ne $vmmServer) {
        if ($vmmServer.IsConnected) {
            $vmmServer.Disconnect()
        }
        $vmmServer = $null
    }
}

<#
.Synopsis
   Exports SCOM Management Server information to json
.DESCRIPTION
   Exports SCOM Management Server information to json
.EXAMPLE
   PS C:\> Get-SCOMManagementServer | Export-SCOMManagementServerInfo
.EXAMPLE
   PS C:\> $managementServerCollection = Get-SCOMManagementServer
   PS C:\> Export-SCOMManagementServerInfo -ManagementServer $managementServerCollection
#>

function Export-SCOMManagementServerInfo
{
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0)]
        [ValidateNotNull()]
        [Microsoft.EnterpriseManagement.Administration.ManagementServer[]]
        $ManagementServer
    )

    Begin{
        $jsonOutput = @()
    }
    Process{
        # This is a hack because ConvertTo-Json does not like converting ManagmentServers.
        # When you pipe to ConvertTo-Json, you get this error:
        # "ConvertTo-Json : An item with the same key has already been added."
        # The multiple pipes below seem to convert to json as currently desired.
        $tmpMgmtServer = $ManagementServer | ConvertTo-Csv | ConvertFrom-Csv

        # Get the .NET Framework version and add a new property to the Management Server object.
        $dotNetFrameworkVersion = Get-DotNetFrameworkVersion -ComputerName $tmpMgmtServer.ComputerName
        $tmpMgmtServer | Add-Member -NotePropertyName DotNetFrameworkVersion -NotePropertyValue $dotNetFrameworkVersion

        # Add the temporary object to the output array
        $jsonOutput += $tmpMgmtServer
    }
    End{
        $jsonOutput | ConvertTo-Json | Out-File .\SCOMManagementServerInfo.json
    }
}

<#
.Synopsis
   Returns the friendly version of the .NET Framework.
.DESCRIPTION
   Converts the value of 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' Release to a string.
#>

function ConvertTo-DotNetFrameworkFriendlyVersionName
{
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [System.UInt32]$Release
    )
    [string]$FriendlyVersionValue = switch ($Release) {
        378389 { ".NET Framework 4.5" }
        378675 { ".NET Framework 4.5.1" }
        378758 { ".NET Framework 4.5.1" }
        379893 { ".NET Framework 4.5.2" }
        393295 { ".NET Framework 4.6" }
        393297 { ".NET Framework 4.6" }
        394254 { ".NET Framework 4.6.1" }
        394271 { ".NET Framework 4.6.1" }
        394802 { ".NET Framework 4.6.2" }
        394806 { ".NET Framework 4.6.2" }
        460798 { ".NET Framework 4.7" }
        460805 { ".NET Framework 4.7" }
        461308 { ".NET Framework 4.7.1" }
        461310 { ".NET Framework 4.7.1" }
        461808 { ".NET Framework 4.7.2" }
        461814 { ".NET Framework 4.7.2" }
        528040 { ".NET Framework 4.8" }
        528049 { ".NET Framework 4.8" }
        528372 { ".NET Framework 4.8" }
        default { "Unknown .NET version: $Release" }
    }

    return $FriendlyVersionValue
}
<#
.Synopsis
   Returns the .NET Framework Version
.DESCRIPTION
   Returns the .NET Framework Version
#>

function Get-DotNetFrameworkVersion
{
    [CmdletBinding()]
    [OutputType([string])]
    Param
    (
        [parameter(Mandatory = $false)]
        [string] $ComputerName = $env:COMPUTERNAME
    )

    $arguments = @{sSubKeyName = "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full"; sValueName ='Release'};

    # Invoke-CimMethod seems to not like FQDNs when $ComputerName is the current machine.
    # For example: assume $ComputerName -eq 'ms1.contoso.com' and $env:COMPUTERNAME -eq 'ms1'.
    # Then Invoke-CimMethod will throw this:
    ########################################################################################
    # Invoke-CimMethod : Access is denied.
    # At line:1 char:1
    # + Invoke-CimMethod -ClassName StdRegProv -MethodName GetDWORDValue -Arg ...
    # + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # + CategoryInfo : PermissionDenied: (root\cimv2:StdRegProv:String) [Invoke-CimMethod], CimException
    # + FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure.CimCmdlets.InvokeCimMethodCommand
    # + PSComputerName : OpsMgr-1.contoso.com
    ########################################################################################
    #
    # This split ensures we always call Invoke-CimMethod with the NetBIOS name even if
    # $ComputerName is already a NetBIOS name.
    [string]$tmpComputerName = $ComputerName.Split('.')[0]

    # https://docs.microsoft.com/en-us/previous-versions/windows/desktop/regprov/stdregprov
    $output = Invoke-CimMethod -ClassName StdRegProv -MethodName GetDWORDValue -Arguments $arguments -ComputerName $tmpComputerName

    $friendlyVersion = ConvertTo-DotNetFrameworkFriendlyVersionName $output.uValue

    return $friendlyVersion
}

<#
.Synopsis
   Gets the SQL Server Version Information
.DESCRIPTION
   This returns the T-SQL @@VERSION
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
#>

function Get-SqlVersion
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([string])]
    Param
    (
        [Parameter(Mandatory=$true,
                   Position=0)]
        [string]
        $ComputerName,
        [Parameter(Mandatory=$false,
                   Position=1)]
        [string]
        $InstanceName
    )

    $connectionStringBuilder = New-Object System.Data.SqlClient.SqlConnectionStringBuilder

    if ($InstanceName) {
        $connectionStringBuilder['Data Source'] = $ComputerName + "\" + $InstanceName
    } else {
        $connectionStringBuilder['Data Source'] = $ComputerName
    }

    $connectionStringBuilder['Initial Catalog'] = 'master'
    $connectionStringBuilder['Application Name'] = 'Scem.Support Module'
    $connectionStringBuilder['Trusted_Connection'] = $true

    [System.Data.SqlClient.SqlCommand]$sqlCommand = $null
    [System.Data.SqlClient.SqlDataReader]$sqlReader = $null
    [string]$sqlVersion = 'Unknown'

    try{
        $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $connectionStringBuilder.ConnectionString
        $sqlConnection.Open()

        [System.Data.SqlClient.SqlCommand]$sqlCommand = $sqlConnection.CreateCommand()
        $sqlCommand.CommandText = 'SELECT @@VERSION'
        $sqlCommand.CommandType = [System.Data.CommandType]::Text

        [System.Data.SqlClient.SqlDataReader]$sqlReader = $sqlCommand.ExecuteReader()
        while($sqlReader.Read()){
            $sqlVersion = $sqlReader.GetString(0)
            break
        }
    }
    finally{
        if($null -ne $sqlReader){
            $sqlReader.Dispose()
        }
        if($null -ne $sqlCommand){
            $sqlCommand.Dispose()
        }
        if($null -ne $sqlConnection){
            $sqlConnection.Dispose()
        }
    }

    return $sqlVersion
}

<#
.Synopsis
   Gets the TLS Settings Information
.DESCRIPTION
   This returns the TLS Settings
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.OWNER
    AndyDesmond
#>

function Get-TLSSetting {
    [CmdletBinding()]
    Param(
        [parameter(Mandatory = $false,Position=0)]
        [string]$ComputerName = $env:COMPUTERNAME
    )

    $ProtocolList = @("SSL 2.0", "SSL 3.0", "TLS 1.0", "TLS 1.1", "TLS 1.2")
    $ProtocolSubKeyList = @("Client", "Server")

    #Initialize the results set
    $TLSSetting = [Ordered]@{}
    # Invoke-CimMethod seems to not like FQDNs when $ComputerName is the current machine.
    # For example: assume $ComputerName -eq 'ms1.contoso.com' and $env:COMPUTERNAME -eq 'ms1'.
    # Then Invoke-CimMethod will throw this:
    ########################################################################################
    # Invoke-CimMethod : Access is denied.
    # At line:1 char:1
    # + Invoke-CimMethod -ClassName StdRegProv -MethodName GetDWORDValue -Arg ...
    # + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # + CategoryInfo : PermissionDenied: (root\cimv2:StdRegProv:String) [Invoke-CimMethod], CimException
    # + FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure.CimCmdlets.InvokeCimMethodCommand
    # + PSComputerName : OpsMgr-1.contoso.com
    ########################################################################################
    #
    # This split ensures we always call Invoke-CimMethod with the NetBIOS name even if
    # $ComputerName is already a NetBIOS name.
    [string]$Target = $ComputerName.Split('.')[0]
    $Protocols = @{}
    ForEach ($Protocol in $ProtocolList) {
        ForEach ($ProtocolSubKey in $ProtocolSubKeyList) {
            $sSubKeyName = "SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$($Protocol)\$($ProtocolSubKey)"
            $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetDWORDValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DisabledByDefault" }
            $Protocols.add("$Protocol.$ProtocolSubKey", $CIMMethod)
        }
    }
    $TLSSetting.Add($Target, $Protocols)

    Return (ConvertTo-Json $TLSSetting)
}

<#
.Synopsis
   Gets the Registry Keys from System Center Product
.DESCRIPTION
   This gets the Registry Keys from System Center Product
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.OWNER
    blakedrumm
#>

function Get-SystemCenterSetupRegKeyInfo
{
    [CmdletBinding()]
    [OutputType([Microsoft.EnterpriseManagement.Support.Common.SystemCenterSetupRegKeyInfo])]
    Param(
    [parameter(Mandatory = $false,Position=0)]
    [string]$ComputerName = $env:COMPUTERNAME
    )

    # This split ensures we always call Invoke-CimMethod with the NetBIOS name even if
    # $ComputerName is already a NetBIOS name.
    [string]$Target = $ComputerName.Split('.')[0]
    $sSubKeyName = "SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup"
    # construct a new object
    $setuplocation = New-Object -TypeName Microsoft.EnterpriseManagement.Support.Common.SystemCenterSetupRegKeyInfo
    #set the object values from the registry key
    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "CurrentVersion" }
    $setuplocation.CurrentVersion = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DatabaseName" }
    $setuplocation.DatabaseName = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DatabaseServerName" }
    $setuplocation.DatabaseServerName = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DatabaseVersion" }
    $setuplocation.DatabaseVersion = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DataWarehouseDBName" }
    $setuplocation.DataWarehouseDBName = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "DataWarehouseDBServerName" }
    $setuplocation.DataWarehouseDBServerName = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "InstallDirectory" }
    $setuplocation.InstallDirectory = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "InstalledOn" }
    $setuplocation.InstalledOn = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "ManagementServerPort" }
    $setuplocation.ManagementServerPort = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "Product" }
    $setuplocation.Product = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "ServerVersion" }
    $setuplocation.ServerVersion = $CIMMethod.sValue

    $CIMMethod = Invoke-CimMethod -ClassName 'StdRegProv' -MethodName GetStringValue -ComputerName $Target -Arguments @{sSubKeyName = $sSubKeyName; sValueName = "UIVersion" }
    $setuplocation.UIVersion = $CIMMethod.sValue

    return $setuplocation
}

<#
.Synopsis
   Gets the resource pools used in SCOM Cross Platform Monitoring
.DESCRIPTION
   Gets the resource pools used in SCOM Cross Platform Monitoring
.EXAMPLE
   Example of how to use this cmdlet
.EXAMPLE
   Another example of how to use this cmdlet
.OWNER
    udmudiar
#>

function Get-SCXResourcePool
{
    [CmdletBinding()]
    [OutputType([String[]])]
    Param()

    $UnixLinuxComputers = Get-SCOMClass -DisplayName "UNIX/Linux Computer" | Get-SCOMClassInstance
    $relationshipType = Get-SCOMRelationship -Name "Microsoft.SystemCenter.ManagementActionPointShouldManageEntity"
    $instances=Get-SCOMRelationshipInstance -TargetInstance $UnixLinuxComputers | Where-Object { $_.RelationshipId -eq $relationshipType.Id }

    return $instances.SourceObject.DisplayName | Get-Unique
}

<#
.Synopsis
   Tests whether the current user is running with elevated privileges
.DESCRIPTION
   Tests whether the current user is running with elevated privileges
.NOTES
   Returns $true if user is running with elevated privileges. $false otherwise.
.OWNER
    cgreene
#>

function Test-IsCurrentUserAdministrator
{
    [CmdletBinding()]
    [OutputType([bool])]
    Param()

    [Security.Principal.WindowsPrincipal]$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    
    [bool] $IsAdministrator = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

    return $IsAdministrator
}