Showing posts with label ps1. Show all posts
Showing posts with label ps1. Show all posts

Monday, August 8, 2016

Powershell - SCOM (OpsMgr) Distributed Application to SCCM (ConfigMgr) Collection

For reporting purposes i had to create equal SCCM collections with the same members that i had in SCOM Distributed Applications.
Now that i have same DA as Collections, and respective members, i can match alerts (DA from SCOM), as well i can have a list of required updates (Collection from SCCM) in the same PowerBI report.
It can be really useful for Application Owners or Sys Admin teams.

Instead of creating by hand every DA I've in SCCM as a collection, and since i've got around 60 DA's, i came up with this script!
(Sorry for the variable names, and for some bad code - not having the time i need to get it better!)
(PS: Read the comments before you run the script! :) )

 Import-Module OperationsManager  
 # Your SCCM Server  
 $SCCMServer = 'Your SCCM Server'  
 $Class = Get-SCOMClass -DisplayName 'User Created Distributed Application'  
 $DistrApps = Get-SCOMClassInstance -Class $Class  
 $DARelationList = ''  
 $ListaDAandHosts = @()  
 Foreach ($DA in $DistrApps) {  
   $DAHosts = ($DA | % {$_.GetRelatedMonitoringObjects()} | % {$_.GetRelatedMonitoringObjects()}).DisplayName  
   Foreach ($Hostz in $DAHosts) {  
     $ListaDAandHosts += $DA.DisplayName + ';' + ($Hostz -split '\.')[0]  
   }  
 }  
 #This is because i only want DA with valid hostnames!  
 $RegexQuery=[regex]"^[0-9A-Za-z].*;(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$"  
 $ListaDA = @()  
 $ListaDA += 'DA;ServerFQDN'  
 Foreach ($line in $ListaDAandHosts) {  
   If ($RegexQuery.Match($line).Success -eq $true) {      
       $ListaDA += $RegexQuery.Match($line).Groups[0].Value  
   }  
 }  
 # Set the out-file as you like!  
 $ListaDA | Out-File "\\\$SCCMServer\c$\FOLDER\ListaDA.csv"  
 $SCCMScriptBlock = {  
   Import-Module "D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1"  
   $DACSV = Import-csv 'C:\GDC\ListaDA.csv' -Delimiter ';'  
   $DAList = ($DACSV | Group {$_.DA.Substring(0)}).Name  
   # Set Location to Site Name #  
   Set-Location YOUR_SITE_NAME:  
   # Your SCCM Limit Collection #  
   $Limitingcollections = "All Systems"  
   # Let the show begin #  
   Foreach ($DA in $DAList) {  
     $DAHostList = @()  
     $DAHosts = (($DACSV | ? { $_.DA -eq $DA } | Select ServerFQDN).ServerFQDN)  
     # Create DA If not Exists #    
     If (Get-CMDeviceCollection -Name $DA) {  
       # Does Nothing #  
       $DA + ' | Already exists!'  
     } Else {  
       $DANewCollection = New-CMDeviceCollection -Name "$DA" -LimitingCollectionName $Limitingcollections  
     }  
     # Add each host to Collection #  
     Foreach ( $SCCMAgent in $DAHosts ){  
       Try {  
         Add-CMDeviceCollectionDirectMembershipRule -CollectionName "$DA" -ResourceID $(get-cmdevice -name "$SCCMAgent").ResourceID  
       } Catch {  
         $SCCMAgent + ' | Already in Collection or not found'  
       }  
     }  
       # Move your collection to specific location - if you want to #  
     Move-CMObject -FolderPath 'SITE_NAME:\DeviceCollection\YOUR_SPECIFIC_FOLDER' -InputObject $DANewCollection  
   }  
 }  
 $SCCMSession = New-PSSession -ComputerName $SCCMServer  
 Invoke-Command -Session $SCCMSession -scriptblock $SCCMScriptBlock  

And, that's it!

Thursday, June 2, 2016

OpsMgr (SCOM) - Management Servers Services Status and System Consumption

Some Operations Manager installations just go off the marks when it comes to memory and processor utilization by SCOM services (omsdk, healthservice and cshost).
So, it might be useful to know what's going on your servers, specially when you apply a new MP, or change any other configuration.
In my particular case i just found out that a bunch of gateway servers went to it's limit in Unix/Linux monitoring.
So, i made this Powershell script that retrieves me :
Management Server | Service Name | Service Status | Service PID | CPU Time | Private Bytes

Basically i just make some WMI queries to each MS i've got and put all the info i retrieve in a fancy HTML table.

Well, the output :

And the most important, the code:
 Import-Module OperationsManager  
 New-SCOMManagementGroupConnection -ComputerName $env:computername  
 $managementServers = (Get-SCOMManagementServer).DisplayName  
 $Head = "<style>"  
 $Head +="BODY{background-color:White;font-family:Verdana,sans-serif; font-size: x-small;}"  
 $Head +="TABLE{font-family: verdana,arial,sans-serif; font-size:9px; color:#333333; border-width: 1px; border-color: #666666; border-collapse: collapse;}"  
 $Head +="TH{border-width: 1px; padding: 8px; border-style: solid; border-color: #666666; background-color: #dedede;}"  
 $Head +="TD{border-width: 1px; padding: 8px; border-style: solid;}"  
 $Head +="</style>"  
 $myStatus = "<br><br>"  
 # Your logo (if any) goes here :)  
 $myStatus += "<img src='.\images\logo' height='12%' width='12%'>"  
 $myStatus += "<center><h1 style=color:#999999>.: (OpsMgr) Management Servers - Services Status :.</center>"  
 $myStatus += "<table>"  
 $myStatus += "<tr>"  
 $myStatus += "<td>Management Server</td>"  
 $myStatus += "<td>Service</td>"  
 $myStatus += "<td>Status</td>"  
 $myStatus += "<td>PID</td>"  
 $myStatus += "<td>Processor Time</td>"  
 $myStatus += "<td>Private Bytes (in MB)</td>"  
 $myStatus += "</tr>"  
 foreach ( $ms in $managementServers ) {  
   $perflist = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process -ComputerName $ms)   
   $services = @("HealthService","OMSDK","cshost")  
   foreach ($service in $services) {   
     $mypid = Get-WmiObject win32_service -ComputerName $ms | ?{$_.Name -like "$service" } | select -ExpandProperty ProcessId  
     $procStatus = (Get-Service -ComputerName $ms -Name $service).Status  
     $cpuCon = ($perflist | ? {$_.IDProcess -eq "$mypid" }).PercentProcessorTime  
     $privBytes = [math]::Round((($perflist | ? {$_.IDProcess -eq "$mypid" }).PrivateBytes / 1MB))  
     $myStatus += "<tr>"  
     $myStatus += "<td>$ms</td>"  
     $myStatus += "<td>$service</td>"  
     $myStatus += "<td>$procStatus</td>"  
     $myStatus += "<td>$mypid</td>"  
     $myStatus += "<td>$cpuCon</td>"  
     $myStatus += "<td>$privBytes</td>"  
     $myStatus += "</tr>"  
   }  
 }  
 $myStatus += "</table>"  
 $HTML = ConvertTo-Html -Head $head -Body $myStatus  
 $HTML > 1.html  

Cheers,

Friday, May 27, 2016

OpsMgr (SCOM) - Unix/Linux Agent Powershell DSC

Who doesn't have any Unix/Linux agent deployment issue ?

Remebering this earlier post i made about "OpsMgr (SCOM) - Unix/Linux Agents Requisites and Troubleshooting"
I came up with the idea to make a script that made this validations for ourselves.

Basically it'll login your unix/linux servers with your own credentials and will make a bunch of configurations tests.
But, please remember that this is my own scenario oriented, so, read and edit the code for your own scenario.

So, in first place, you'll need this library :
http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library

You can put it on your Modules favourite folder (eg. C:\Program Files\WindowsPowerShell\Modules)

Finally!
You can execute this script from your Unix/Linux Resource Pool gateway or MS:

 $ServerList = 'C:\Powershell\SCXAgentDSC\list.txt'  
 $SCXAgents = Get-Content -Path $ServerList  
   
 # Change values for your own  
 $user = 'Your_Run_AsAccountGoesHere!'   
 $pass = ConvertTo-SecureString 'YourPassword' -AsPlainText -Force   
 $creds = New-Object System.Management.Automation.PsCredential($user,$pass)  
   
 try { Import-Module SSH-Sessions }  
 Catch { 'No SSH Modules Found' ; Exit }  
 foreach ( $scxagent in $SCXAgents ) {  
   $scxdomain = ($scxagent -split "\.")[-2..-1] -join '.'  
     # Change values for your own here as well   
   if( (New-SshSession -ComputerName $scxagent -Username Your_Run_AsAccountGoesHere -Password "YourPassword") -notmatch “successfully”) {  
     $scxagent + ' Could not SSH (bad user / password ? | Or no route ? )'  
     $SSHStatus = "1"  
   } Else { $SSHStatus = "0" }  
   If ($SSHStatus -eq "0" ) {  
     Invoke-SshCommand -Quiet -ComputerName $scxagent -Command "sudo -l" | Out-File C:\Powershell\sudo.txt  
     Invoke-SshCommand -Quiet -ComputerName $scxagent -Command "cat /etc/issue" | Out-File C:\Powershell\issue.txt  
     Invoke-SshCommand -Quiet -ComputerName $scxagent -Command "openssl x509 -noout -in /etc/opt/microsoft/scx/ssl/scx.pem -subject -issuer -dates" | Out-File C:\Powershell\certconfig.txt  
         # This is only applied if you have limited sudo configuration   
         # This line will check if the sudo config escapes the EC (error code) variable   
     $ECCount = (Get-Content C:\Powershell\sudo.txt | select-string -SimpleMatch "EC\=0" | measure).Count  
         # This will check if you have enought perms for RPM install and uninstall  
     $RPMLines = Get-Content C:\Powershell\sudo.txt | select-string -SimpleMatch "--force /tmp/scx-monuser/scx"  
         # This will check if you have root permissions (and no further sudo config is needed - so comment the lines that does not match your scenario)  
         $SUDOALL = Get-Content C:\Powershell\sudo.txt | select-string -SimpleMatch "(root) NOPASSWD: ALL"  
         # This will check if you can re-generate certificates if needed  
     $SSLConfig = Get-Content C:\Powershell\sudo.txt | select-string -SimpleMatch "/opt/microsoft/scx/bin/tools/scxsslconfig"  
         # This will check if you have a certificate and for the correct FQDN  
     $CertConfig = Get-Content C:\Powershell\certconfig.txt | select-string -SimpleMatch "$scxagent"  
     $SCXSSLDomain = ((Get-Content C:\Powershell\certconfig.txt | Select-String -SimpleMatch "subject") -split "=")[-1]  
         # Port testing (22 and 1270)  
     Try { If ((new-object System.Net.Sockets.TcpClient("$scxagent","1270")).connected -eq $true ) { $AgentPortStatus = "OK" } Else { $AgentPortStatus = "NOT OK" } } Catch { $AgentPortStatus = "NOT OK"}  
     Try { If ((new-object System.Net.Sockets.TcpClient("$scxagent","22")).connected ) { $sshstatus = "OK"} Else { $sshstatus = "NOT OK" } } Catch { $sshstatus = "NOT OK" }  
         # WSMan Testing   
     If ( Test-WSMan -Port 1270 -ComputerName $scxagent -Authentication Basic -Credential $creds -UseSSL -ErrorAction SilentlyContinue ) { $wsmanstatus = 'OK' } Else { $wsmanstatus = 'NOT OK' }  
     $scxagenturi = "https://"+"$scxagent"+":1270/wsman"  
         # WinRM validation  
     Try { If ( winrm enumerate http://schemas.microsoft.com/wbem/wscim/1/cim-schema/2/SCX_Agent?__cimnamespace=root/scx -username:'YOUR_USERNAME_HERE' -password:'YOUR_PASSWORD_HERE' -r:$scxagenturi -auth:basic -skipCACheck -skipCNCheck -skiprevocationcheck -encoding:utf-8 ) { $winrmstatus = "OK" } Else { $winrmstatus = "NOT OK" } } Catch { $winrmstatus = "NOT OK" }  
     If ( $ECCount -gt "0" )        { $ecstatus = "NOT OK" } Else { $ecstatus = "OK" }  
         If ( $SUDOALL )            { $sudoallstatus = "OK" } Else { $sudoallstatus = "NOT OK" }  
     If ( $RPMLines -match "[0-9]" )    { $rpmstatus = "NOT OK" } Else { $rpmstatus = "OK" }  
     If ( $SSLConfig -match "scxsslconfig" ) { $SSLConfigStatus = "OK" } Else { $SSLConfigStatus = "NOT OK" }  
     If ( $CertConfig -match "$scxagent" -and $CertConfig -match $scxdomain) { $CertificateStatus = "OK" } Else { $CertificateStatus = "NOT OK" }  
         # Remove the ones that not match your cenario (For sudo config)  
     Write-Output "$scxagent | WSMAN : $wsmanstatus | SSH : $sshstatus | AgentPort : $AgentPortStatus | EC SUDOConfig : $ecstatus | RPM SUDOConfig : $rpmstatus | SUDOAll : $sudoallstatus | SCXConfig SUDOConfig : $SSLConfigStatus | Certificate : $CertificateStatus | WinRM : $winrmstatus"  
   }  
 }  
 Remove-SshSession -RemoveAll | Out-Null  


OpsMgr (SCOM) - (Bulk) Set Failover Management Server Powershell Script

I believe every SCOM Admin needs this.

This a script that for every agent you have, if it doesn't have a failover Management Server, it'll set it one.

NOTE : Please read comments inline before you run this

Enjoy!

 try{  
   [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null  
   [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.EnterpriseManagement.Core') | Out-Null  
   [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.EnterpriseManagement.OperationsManager') | Out-Null  
   [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.EnterpriseManagement.Runtime') | Out-Null  
 } Catch { '[OpsMgr] - DLL could not be loaded' }  
 try{  
   $MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings("$env:computername")  
   $MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)  
 } Catch { '[OpsMgr] - Could not connect to Management Group' }  
 # Let's say .. you want to have a list of MS Servers you dont want to work as failover (in my case i don't want Network RP MS servers ... - It's up to you!) :)  
 $IgnoredMS = @('Server1','Server2')  
 # Criteria for every MS you got  
 $MSCriteria = New-Object Microsoft.EnterpriseManagement.Administration.ManagementServerCriteria("Name LIKE '%'")  
 # Let's say you only want to work on specific criteria  
 $MSCriteria = New-Object Microsoft.EnterpriseManagement.Administration.ManagementServerCriteria("Name LIKE 'OpsMgrServer%'")  
 $ManagementServers = ($MG.Administration.GetManagementServers($MSCriteria)).DisplayName | ? { $_ -notin $IgnoredMS }  
 $AgentCriteria = New-Object Microsoft.EnterpriseManagement.Administration.AgentManagedComputerCriteria("Name LIKE '%'")  
 $Agents = $MG.Administration.GetAgentManagedComputers($AgentCriteria) | ? { $_.PrimaryManagementServerName -in @($ManagementServers) }  
 # My logic is :  
 #     - Specific agent will only have a failover MS with the same domain  
 #    So you may need to edit code before running this.  
 Foreach ( $agent in $Agents ) {  
   If ( !($agent.GetFailoverManagementServers()) ) {  
     $PrimaryMS = $agent.PrimaryManagementServerName  
     $Domain = ($PrimaryMS -split "\.")[-2..-1] -join '.'  
     $FailoverMS = ($ManagementServers | Select-String -Pattern "$Domain" | ? { $_ -notin $PrimaryMS })[0]  
     $PrimaryMSCriteria = New-Object Microsoft.EnterpriseManagement.Administration.ManagementServerCriteria("Name = '$PrimaryMS'")  
     $PrimaryManagementServerID = $MG.Administration.GetManagementServers($PrimaryMSCriteria).ID  
     $PrimaryManagementServer = $MG.Administration.GetManagementServer($PrimaryManagementServerID)  
     $FailoverMSCriteria = New-Object Microsoft.EnterpriseManagement.Administration.ManagementServerCriteria("Name = '$FailoverMS'")  
     $FailoverMSIList = New-Object 'Collections.Generic.List[Microsoft.EnterpriseManagement.Administration.ManagementServer]'  
     $MG.Administration.GetManagementServers($FailoverMSCriteria) | % { $FailoverMSIList.Add($_) }  
     $agent.SetManagementServers($PrimaryManagementServer, $FailoverMSIList)  
   } Else { "$(($agent).DisplayName)" + ' has already a Failover MS configured' + "$($agent.GetFailoverManagementServers().DisplayName)" }  
 }  

Cheers!

Monday, May 23, 2016

OpsMgr (SCOM) - Solve the "An Item With The Same Key Has Already Been Added" error


For some reasons, like, having a bunch of procedures that include Unix/Linux servers into SCOM, you might get the 'An Item With The Same Key Has Already Been Added' error when you go to Administration - Unix/Linux Agents.

That means that you've duplicate unix/linux servers in your SCOM installation.

The only way to solve this is to find the duplicate entry, and delete them both.

To do that, you can't use the Get-SCXAgent, this will output unique values only - the only way to solve this is going to your OpsDB execute a querry (bellow), and foreach value you get, you need to run the 'get-scxagent "duplicate_value" | Remove-ScxAgent' cmdlet.

So, first things first.

The query :

 DECLARE @ClassName NVARCHAR(256)   
 DECLARE @CManagedTypeId UNIQUEIDENTIFIER   
 SET @ClassName = 'Microsoft.Unix.OperatingSystem'  
 SET @CManagedTypeId = (   
     SELECT ManagedTypeId  
     FROM ManagedType   
     WHERE TypeName = @ClassName )   
 SELECT  
     [ManagedEntityGenericView].[Id],   
     [ManagedEntityGenericView].[Name],   
     [ManagedEntityGenericView].[Path],   
     [ManagedEntityGenericView].[FullName],   
     [ManagedEntityGenericView].[LastModified],   
     [ManagedEntityGenericView].[TypedManagedEntityId],   
     NULL AS SourceEntityId   
 FROM  
     dbo.ManagedEntityGenericView   
 INNER JOIN (      
     SELECT DISTINCT [BaseManagedEntityId]   
     FROM dbo.[TypedManagedEntity] TME WITH(NOLOCK)   
     JOIN [dbo].[DerivedManagedTypes] DT ON DT.[DerivedTypeId] = TME.[ManagedTypeId]   
     WHERE  
         DT.[BaseTypeId] = @CManagedTypeId  
         AND TME.IsDeleted = 0 )  
 AS ManagedTypeIdForManagedEntitiesByManagedTypeAndDerived   
 ON ManagedTypeIdForManagedEntitiesByManagedTypeAndDerived.[BaseManagedEntityId] = [Id]   
 WHERE  
     [IsDeleted] = 0 AND  
     [TypedMonitoringObjectIsDeleted] = 0 AND  
     [ManagedEntityGenericView].[Path] IN (   
                                             SELECT [BaseManagedEntity].[Path]   
                                             FROM [BaseManagedEntity]   
                                             GROUP BY [BaseManagedEntity].[Path]   
                                             HAVING COUNT([BaseManagedEntity].[Path]) > 1   
                                          )  
 GROUP BY [ManagedEntityGenericView].[Id],   
     [ManagedEntityGenericView].[Name],   
     [ManagedEntityGenericView].[Path],   
     [ManagedEntityGenericView].[FullName],   
     [ManagedEntityGenericView].[LastModified],   
     [ManagedEntityGenericView].[TypedManagedEntityId]  
 HAVING COUNT([ManagedEntityGenericView].[Path]) > 1  

Now that you've the duplicate values to delete, just open a powershell prompt and run the follow cmdlet foreach duplicate value you've.

 get-scxagent "Your_Server" | Remove-ScxAgent  

And, your problem is solved.

Cheers,

Thursday, April 7, 2016

OpsMgr (SCOM) - Create Performance Charts in Powershell

It might be usefull for people who don't have Datazen or just want to create and manage their own costumized HTML views, or perhaps, for fun!

Powershell is one of the things i like the most while exploring everything that SCOM (and other System Center tools) can give to you, it just makes everything you want, a way or another.

So.

What about creating this in a Powershell script ?











This is the script that does all the magic :

!!NOTE!! : For the most problematic servers in specific groups i've i retrieve memory, cpu, and disk usage performance data, but, you change this logic as well as the performance counters.

Please attempt to the comments in-line so you can understand the logic :)
 [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")  
 Import-Module OperationsManager  
 New-SCOMManagementGroupConnection -ComputerName "opsmgr.server.local" #Change here :)  
 $script:scriptpath = "C:\PS\OpsMgr_PerfCharts\images"  
   
 # Foreach Group above list the most problematic agents   
   
 $MyGroups = @()  
 $MyGroups += Get-SCOMGroup -DisplayName 'UNIX/Linux Computer Group'  
 $MyGroups += Get-SCOMGroup -DisplayName 'All Windows Computers'  
 $newTime = (Get-Date).AddHours(-24)  
 $Criteria = New-Object Microsoft.EnterpriseManagement.Monitoring.MonitoringAlertCriteria("TimeRaised > `'$newTime`'")  
 $TransversalDepth = [Microsoft.EnterpriseManagement.Common.TraversalDepth]::Recursive  
 $TopAgents = @()  
 Foreach ( $Group in $MyGroups ) {  
   $TopObjAlerts = ($Group.GetMonitoringAlerts($Criteria , $TransversalDepth) | Group-Object MonitoringObjectPath | Sort-Object count -descending | select -first 5 Values).Values  
   Foreach ($i in $TopObjAlerts) {  
     $TopAgents += ($i -split ";")[0]  
   }  
   $TopAgents = $TopAgents.Split(";",[System.StringSplitOptions]::RemoveEmptyEntries)  
 }  
 $Count = 0  
 $Query = ""  
 Foreach ($Agent in $TopAgents) {  
   If ($TopAgents.Count -eq $Count ) {  
     $Query += "'" + $agent + "'" + ","  
   } Else { $Query += "'" + $agent + "'" }  
   $Count++  
 }  
   
 # Create SQL Query with the most problematic agents criteria   
   
 $Query = $Query -replace "''","','"  
   
 $SqlQuery = "  
 SELECT          
     Path,  
     DateTime,  
     CASE   
     WHEN vpr.ObjectName = 'Processor Information' THEN 'Processor'  
     WHEN vpr.ObjectName = 'LogicalDisk' THEN 'Logical Disk' ELSE vpr.ObjectName END as ObjectName,  
 CASE   
     WHEN vpr.CounterName = 'PercentMemoryUsed' OR vpr.CounterName = '% Available Memory' THEN '% Used Memory'   
     WHEN vpr.CounterName = '% Free Space' THEN '% Used Space'  
     ELSE vpr.CounterName END as CounterName,  
 CASE   
     WHEN len(vpri.InstanceName) < 1 THEN '_Total' ELSE vpri.InstanceName END as InstanceName,  
 CASE   
     WHEN vpr.CounterName = '% Available Memory' or vpr.CounterName = '% Free Space' THEN 100 - pvpr.AverageValue ELSE pvpr.AverageValue END as AverageValue,  
 100.00 as ComparisonValue  
 FROM   
     Perf.vPerfDaily pvpr WITH (NOLOCK)   
     inner join vManagedEntity vme WITH (NOLOCK) on pvpr.ManagedEntityRowId = vme.ManagedEntityRowId   
     inner join vPerformanceRuleInstance vpri WITH (NOLOCK) on pvpr.PerformanceRuleInstanceRowId = vpri.PerformanceRuleInstanceRowId   
     inner join vPerformanceRule vpr WITH (NOLOCK) on vpr.RuleRowId = vpri.RuleRowId   
 WHERE  
     Path in (  
         select   
             unix.DisplayName  
         from   
             vManagedEntity unix WITH (NOLOCK)   
             join vManagedEntityManagementGroup unixMG WITH (NOLOCK) ON unix.ManagedEntityRowId = unixMG.ManagedEntityRowId  
             join vManagedEntityType unixType WITH (NOLOCK) on unix.ManagedEntityTypeRowId = unixType.ManagedEntityTypeRowId  
         where   
             unixMG.ToDateTime Is Null   
             and (unixType.ManagedEntityTypeSystemName = 'Microsoft.Unix.Computer'   
             or unixType.ManagedEntityTypeSystemName = 'Microsoft.Windows.Computer' )  
             AND vpr.ObjectName <> 'Process'  
             AND unix.DisplayName IN ( $Query )  
     )  
 AND vpr.CounterName in ('% Processor Time','PercentMemoryUsed','% Available Memory','% Free Space')  
 AND vpri.InstanceName in ('_Total','C:','/','')  
 AND DATEDIFF(DAY, pvpr.DateTime, GETDATE()) < 8  
 "  
   
 $SqlQuery > $env:TEMP\query.sql  
   
 $SqlQuery = Get-Content $env:TEMP\query.sql  
   
 # Create connection to SCOMDW Database   
   
 $script:SQLServer = "SCOMDBSERVER\SCOMDW"  
 $script:SQLDBName = "OperationsManagerDW"  
 $script:connString = "Data Source=$SQLServer;Initial Catalog=$SQLDBName;Integrated Security = True"  
 $script:connection = New-Object System.Data.SqlClient.SqlConnection($connString)  
 $connection.Open()  
 $sqlcmd = $connection.CreateCommand()  
 $sqlcmd.CommandText = $SqlQuery  
 $results = $sqlcmd.ExecuteReader()  
 $script:table = new-object “System.Data.DataTable”  
 $script:table.Load($results)  
   
 # Lets GRAPH!  
   
 $Servers = ($table | Select -Unique Path).Path  
 # 1 Graph foreach Agent   
 Foreach ( $Server in $Servers ) {  
   $Server = ($Server -split '\.')[0]  
   $GraphName = $Server  
   # Create CHART   
   $GraphName = New-object System.Windows.Forms.DataVisualization.Charting.Chart  
   $GraphName.Width = 900  
   $GraphName.Height = 300  
   $GraphName.BackColor = [System.Drawing.Color]::White  
   # CHART Title  
   [void]$GraphName.Titles.Add("$Server - Performance Data")  
   $GraphName.Titles[0].Font = "Arial,10pt"  
   $GraphName.Titles[0].Alignment = "MiddleCenter"  
   # CHART Area and X/Y sizes   
   $chartarea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea  
   $chartarea.Name = "ChartArea"  
   $chartarea.AxisY.Title = "$CounterName"  
   $chartarea.AxisX.Title = "Time"  
   $chartarea.AxisY.Maximum = 100  
   $chartarea.AxisY.Interval = 10  
   $chartarea.AxisX.Interval = 1  
   $GraphName.ChartAreas.Add($chartarea)  
   # CHART Legend  
   $legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend  
   $legend.name = "Legend"  
   $GraphName.Legends.Add($legend)  
     # Line Colors  
     $num = 0  
   $LineColours = ('DarkBlue','Brown','DarkMagenta')  
   # Create 'n' SERIES (lines) for each COUNTER  
   Foreach ($Counter in $Counters) {  
     $LineColor = $LineColours[$num]  
     [void]$GraphName.Series.Add("$Counter")  
     $GraphName.Series["$Counter"].ChartType = "Line"  
     $GraphName.Series["$Counter"].BorderWidth = 2  
     $GraphName.Series["$Counter"].IsVisibleInLegend = $true  
     $GraphName.Series["$Counter"].chartarea = "ChartArea"  
     $GraphName.Series["$Counter"].Legend = "Legend"  
     $GraphName.Series["$Counter"].color = "$LineColor"  
     ForEach ($i in ($table | ? { $_.ObjectName -eq $Counter -and $_.Path -like "$Server*" }) ) {   
       $GraphName.Series["$Counter"].Points.addxy( ($i.DateTime -split ' ')[0] , $i.AverageValue )   
     }  
     $num++ # Next Color :)  
   }  
   $GraphName.SaveImage("$scriptpath\$Server.png","png") # Save the GRAPH as PNG  
 }  

Have fun! :)