Public/Get-SCOMRunAsProfilesAccounts.ps1

Function Get-SCOMRunAsProfilesAccounts {
  <#
      .DESCRIPTION
      Will output all RunAs accounts and any associated Security Profiles.
 
      .EXAMPLE
      Get-SCOMRunAsProfilesAccounts
 
      The above example will connect to localhost and output RunAs account and Seucrity Profile information.
 
      .EXAMPLE
      Get-SCOMRunAsProfilesAccounts -ManagementServer 'ms01.contoso.com'
 
      The above example will connect to the designated server and output RunAs account and Seucrity Profile information.
 
      .EXAMPLE
      Get-SCOMRunAsProfilesAccounts | Out-Gridview -Passthru
 
      The above example will display results in Gridview. Any selected rows can be passed through to the PowerShell Console for further review or manipulation.
 
      .INPUTS
      System.String
      .OUTPUTS
      Custom object
      .NOTES
      Author: Tyson Paul, derived from the works of Kevin Holman, Dirk Brinkman, Mihai (Sarbulescu?)
      Blog: https://monitoringguys.com/
      History:
      2020.02.25 - Revision of previous version (v1.0, Kevin Holman); improved efficiency, modified formatting.
      Ref: Kevin Holman: https://kevinholman.com/2017/07/27/document-your-scom-runas-account-and-profiles-script/
 
      .FUNCTIONALITY
      This function works best when piped to Out-Gridview or exported to CSV.
      .LINK
      Get-SCOMRunAsAccountName
  #>



  Param(
    [string]$ManagementServer = 'LOCALHOST'
  )


  ############# FUNCTIONS ###################
  Function Get-ClassfromInstance{
    [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
        SupportsShouldProcess=$true,
        PositionalBinding=$false,
    ConfirmImpact='Medium')]
    [OutputType([tinyClass])]

    Param (
      $Instance
    )
    $class = (Get-SCOMClass -Id $instance.LeastDerivedNonAbstractMonitoringClassId)
    $tmpClass = [tinyClass]::new()
    $tmpClass.Id = $class.Id
    $tmpClass.Name = $class.Name
    If ($class.DisplayName.Length -ne 0) {
      $tmpClass.DisplayName = $class.DisplayName
    }

    Return $tmpClass
  }
  ########### END FUNCTIONS #################


  ########### BEGIN MAIN #################

  # My custom object
  Class Account {
    [string]$RunAsAccountName = ''
    [string]$Domain = ''
    [string]$Username = ''
    [string]$AccountType = ''
    [string]$ProfileName = ''
    [string]$ProfileDisplayName = ''
    [string]$TargetClassID = ''
    [string]$TargetClassName = ''
    [string]$TargetClassDisplayName = ''
    [string]$TargetID = ''
    [string]$TargetName = ''
    [string]$TargetDisplayName = ''
  }

  Class tinyClass {
    [string]$Id = ''
    [string]$Name = ''
    [string]$DisplayName = ''
  }

  # Main array for account collection
  [System.Collections.ArrayList]$AccountDataArray = @()

  # Load Modules and Connect to SCOM
  . Import-SCOMPowerShellModule

  # Remove any existing/default mgmt group connection
  Get-SCOMManagementGroupConnection | Remove-SCOMManagementGroupConnection

  # Connect to designated mgmt server (explicit)
  $MGConnection = New-SCManagementGroupConnection -ComputerName $ManagementServer

  $MG = Connect-OMManagementGroup -SDK $ManagementServer

  # Load Assembly and define ManagementGroup Object
  $CoreDLL = 'Microsoft.EnterpriseManagement.Core'
  $null = [reflection.assembly]::LoadWithPartialName($CoreDLL)
  $EMG = New-Object -TypeName Microsoft.EnterpriseManagement.EnterpriseManagementGroup -ArgumentList ($ManagementServer)

  #Process HealthService based Action Accounts Section
  #=======================================================
  ForEach ($RunAsProfile in (Get-SCOMRunAsProfile))
  {
    # Get Health Service array associated with the profile
    $HSRef = $MG.GetMonitoringSecureDataHealthServiceReferenceBySecureReferenceId($RunAsProfile.ID)
    ForEach ($HS in $HSRef)
    {
      $TargetName = (Get-SCOMClassInstance -Id $HS.HealthServiceId).Displayname
      $MonitoringData = $HS.GetMonitoringSecureData()
      $tempAccount = [Account]::new()
      $tempAccount.RunAsAccountName = $MonitoringData.Name
      $tempAccount.Domain = $MonitoringData.Domain
      $tempAccount.Username = $MonitoringData.UserName
      $tempAccount.AccountType = $MonitoringData.SecureDataType
      $tempAccount.ProfileName = $RunAsProfile.Name
      $tempAccount.TargetID = $HS.HealthServiceId.Guid.ToString()
      $tempAccount.TargetName = $TargetName
      $tempAccount.TargetDisplayName = ''
      $tmpClass = Get-ClassfromInstance -Instance (Get-SCOMClassInstance -Id $HS.HealthServiceId)
      $tempAccount.TargetClassId = $tmpClass.Id
      $tempAccount.TargetClassName = $tmpClass.Name
      $tempAccount.TargetClassDisplayName = $tmpClass.DisplayName

      If ($null -ne $RunAsProfile.DisplayName )
      {
        $tempAccount.ProfileDisplayName = $RunAsProfile.DisplayName
      }

      #$AccountDataArray += $tempAccount
      $null = $AccountDataArray.Add($tempAccount)
    }
  }
  #=======================================================
  # End ForEach RunAsProfile

  # Process all RunAsAccounts targeted at other targets
  #=======================================================
  #Get all RunAsAccounts
  $colAccounts = $EMG.Security.GetSecureData()

  #Loop through each RunAs account
  ForEach ($account in $colAccounts)
  {
    $secStorId = $account.SecureStorageId
    $stringBuilder = New-Object -TypeName System.Text.StringBuilder
    $secStorId | ForEach-Object {$null = $stringBuilder.Append($_.ToString('X2'))}
    $MPCriteria = "Value='{0}'" -f $stringBuilder.ToString()
    $moc = New-Object -TypeName Microsoft.EnterpriseManagement.Configuration.ManagementPackOverrideCriteria -ArgumentList ($MPCriteria)
    $overrides = $EMG.Overrides.GetOverrides($moc)

    If ($overrides.Count -eq 0)
    {
      $tempAccount = [Account]::new()
      $tempAccount.RunAsAccountName = $account.Name
      $tempAccount.Domain = $account.Domain
      $tempAccount.Username = $account.UserName
      $tempAccount.AccountType = $account.SecureDataType
      $tempAccount.ProfileName = 'No Profile Assigned'

      $null = $AccountDataArray.Add($tempAccount)
    }
    # Customizations/overrides exist for the account, process them all.
    Else
    {
      ForEach ($override in $overrides)
      {
        # Every account will typically have these values
        $tempAccount = [Account]::new()
        $tempAccount.RunAsAccountName = $account.Name
        $tempAccount.Domain = $account.Domain
        $tempAccount.Username = $account.UserName
        $tempAccount.AccountType = $account.SecureDataType
        $tempAccount.TargetClassId = $override.Context.Id.Guid.ToString()
        $tmpClass = Get-SCClass -Id $tempAccount.TargetClassId
        $tempAccount.TargetClassName = $tmpClass.Name

        If ($null -ne $tmpClass.DisplayName)
        {
          $tempAccount.TargetClassDisplayName = $tmpClass.DisplayName
        }


        # If a ContextInstance (specific object) exists, add instance-specific data.
        If ($null -ne $override.ContextInstance)
        {
          $tempAccount.TargetID = $override.ContextInstance.Guid.ToString()
          $TargetClassInstance = Get-SCOMClassInstance -Id $tempAccount.TargetID
          $tempAccount.TargetName = $TargetClassInstance.Name

          If ($null -ne $TargetClassInstance.DisplayName)
          {
            $tempAccount.TargetDisplayName = $TargetClassInstance.DisplayName
          }
        }

        $secRef = $EMG.Security.GetSecureReference($override.SecureReference.Id)
        $tempAccount.ProfileName = $secRef.Name
        If ($null -ne $secRef.DisplayName)
        {
          $tempAccount.ProfileDisplayName = $secRef.DisplayName
        }

        # Add item to array
        $null = $AccountDataArray.Add($tempAccount)
      }
    } #End ForEach Override
  }
  #=======================================================
  # End ForEach account


  # Sort by RunAsAccountName. This is a nice touch for the user.
  Return ($AccountDataArray | Sort-Object -Property RunAsAccountName)

}