Hi,
I am developing a powershell based managment pack to monitor cloud resources and I need authentication in place.
Have anyone used basic runAsAccount in a PS discovery or script? I have played around a little but I get this error event 1102
Rule/Monitor "Discovery" running for instance "CLASS" with id:"{A52346E3-5E4C-37EC-E870-97AB46DCA768}" cannot be initialized and will not be loaded. Management group "SCOM"
I have created a run as profile
<SecureReferences> <SecureReference ID="Application.RunasProfile" Accessibility="Public" Context="Application.Class" /> </SecureReferences>
And added parameters to my script datasource
<!--RUNAS ACCOUNT PARAMETERS--> <Parameter> <Name>QueryUser</Name> <Value>$RunAs[Name="Application.RunasProfile"]/UserName$</Value> </Parameter> <Parameter> <Name>QueryPwd</Name> <Value>$RunAs[Name="Application.RunasProfile"]/Password$</Value> </Parameter>
Before using them as parameters in my script
param($sourceId, $managedEntityId, $computerName, $QueryUser, $QueryPwd, $ClientID, $TenantID) $tenantId = $TenantID $client_id = $ClientID $username = $QueryUser $password = Convertto-securestring $QueryPwd -asplaintext -force $creds = New-Object System.Management.Automation.PSCredential ($username, $password)
HELP! my basic management pack gives me headaches
EDIT: Full class/discovery and script
<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3Org/2001/XMLSchema"> <!-- In this fragment you need to replace ##Application##, ##ApplicationComponent##, ##RegistryKey##, ##SourceClass## --> <!-- This fragment will discover a class instance (or instances) based on existence of a registry KEY --> <!-- This fragment depends on references: Windows! = Microsoft.Windows.Library System! = System.Library --> <TypeDefinitions> <EntityTypes> <ClassTypes> <ClassType ID="Office365.CSPCustomer.Class" Base="Windows!Microsoft.Windows.ApplicationComponent" Accessibility="Internal" Abstract="false" Hosted="true" Singleton="false"> <Property ID="CustomerName" Key="true" Type="string" /> <Property ID="URL" Key="false" Type="string" /> <Property ID="CSPID" Key="false" Type="string" /> <Property ID="ManagedServices" Key="false" Type="string" /> </ClassType> <!-- We choose Microsoft.Windows.LocalApplication as our generic base class --> </ClassTypes> <RelationshipTypes> <RelationshipType ID="Office365.CSPCustomer.Realtionship" Base="System!System.Hosting" Accessibility="Internal" Abstract="false"> <Source ID="Source" Type="Office365.WatcherNode.Class" /> <Target ID="Target" Type="Office365.CSPCustomer.Class" /> </RelationshipType> </RelationshipTypes> </EntityTypes> </TypeDefinitions> <Monitoring> <Discoveries> <Discovery ID="Office365.CSPCustomer.Class.Discovery" Target="Office365.WatcherNode.Class" Enabled="true" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <!-- We choose Microsoft.Windows.ServerOperatingSystem as the preferred target class to ensure this will run on all Windows Servers, but wont create duplicates on clusters --> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryClass TypeID="Office365.CSPCustomer.Class" /> </DiscoveryTypes> <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider" RunAs="_CSP_Office365.CSPUser.RunasProfile"> <IntervalSeconds>14400</IntervalSeconds> <SyncTime /> <ScriptName>GetCSPCustomer.ps1</ScriptName> <ScriptBody>$IncludeFileContent/Scripts/GetCSPCustomer.ps1$</ScriptBody> <Parameters> <Parameter> <Name>sourceID</Name> <Value>$MPElement$</Value> </Parameter> <Parameter> <Name>managedEntityID</Name> <Value>$Target/Id$</Value> </Parameter> <Parameter> <Name>computerName</Name> <Value>$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$</Value> </Parameter> <!--RUNAS ACCOUNT PARAMETERS--> <Parameter> <Name>QueryUser</Name> <Value>$RunAs[Name="_CSP_Office365.CSPUser.RunasProfile"]/UserName$</Value> </Parameter> <Parameter> <Name>QueryPwd</Name> <Value>$RunAs[Name="_CSP_Office365.CSPUser.RunasProfile"]/Password$</Value> </Parameter> <!--Use the client and tenant id from watcher node--> <Parameter> <Name>ClientID</Name> <Value>$Target/Property[Type="Office365.WatcherNode.Class"]/ClientID$</Value> </Parameter> <Parameter> <Name>TenantID</Name> <Value>$Target/Property[Type="Office365.WatcherNode.Class"]/PartnerDomain$</Value> </Parameter> </Parameters> <TimeoutSeconds>300</TimeoutSeconds> <StrictErrorHandling>true</StrictErrorHandling> </DataSource> </Discovery> <!-- Additional property discovery --> <Discovery ID="Office365.CSPCustomer.Services.Class.Discovery" Target="Office365.WatcherNode.Class" Enabled="false" ConfirmDelivery="false" Remotable="true" Priority="Normal"> <Category>Discovery</Category> <DiscoveryTypes> <DiscoveryClass TypeID="Office365.CSPCustomer.Class" /> </DiscoveryTypes> <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider" RunAs="_CSP_Office365.CSPUser.RunasProfile"> <IntervalSeconds>21600</IntervalSeconds> <SyncTime>08:20</SyncTime> <ScriptName>GetCSPCustomerServices.ps1</ScriptName> <ScriptBody>$IncludeFileContent/Scripts/GetCSPCustomerServices.ps1$</ScriptBody> <Parameters> <Parameter> <Name>sourceID</Name> <Value>$MPElement$</Value> </Parameter> <Parameter> <Name>managedEntityID</Name> <Value>$Target/Id$</Value> </Parameter> <Parameter> <Name>computerName</Name> <Value>$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$</Value> </Parameter> <!--RUNAS ACCOUNT PARAMETERS--> <Parameter> <Name>QueryUser</Name> <Value>$RunAs[Name="_CSP_Office365.CSPUser.RunasProfile"]/UserName$</Value> </Parameter> <Parameter> <Name>QueryPwd</Name> <Value>$RunAs[Name="_CSP_Office365.CSPUser.RunasProfile"]/Password$</Value> </Parameter> <!--Use the client and tenant id from watcher node--> <Parameter> <Name>ClientID</Name> <Value>$Target/Property[Type="Office365.WatcherNode.Class"]/ClientID$</Value> </Parameter> <Parameter> <Name>TenantID</Name> <Value>$Target/Property[Type="Office365.WatcherNode.Class"]/PartnerDomain$</Value> </Parameter> </Parameters> <TimeoutSeconds>600</TimeoutSeconds> <StrictErrorHandling>true</StrictErrorHandling> </DataSource> </Discovery> </Discoveries> </Monitoring> <LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <DisplayString ElementID="Office365.CSPCustomer.Class"> <Name> CSP Customer</Name> <Description> CSP customer</Description> </DisplayString> <!-- additional properties --> <DisplayString ElementID="Office365.CSPCustomer.Class" SubElementID="CustomerName"> <Name>Customer Name</Name> <Description></Description> </DisplayString> <DisplayString ElementID="Office365.CSPCustomer.Class" SubElementID="URL"> <Name>URL</Name> <Description></Description> </DisplayString> <DisplayString ElementID="Office365.CSPCustomer.Class" SubElementID="CSPID"> <Name>CSPID</Name> <Description></Description> </DisplayString> <DisplayString ElementID="Office365.CSPCustomer.Class" SubElementID="ManagedServices"> <Name>Managed Services</Name> <Description>All customers services on CSP subscription</Description> </DisplayString> <DisplayString ElementID="Office365.CSPCustomer.Class.Discovery"> <Name> CSP customer Discovery</Name> <Description>Discovers CSP customer</Description> </DisplayString> <DisplayString ElementID="Office365.CSPCustomer.Services.Class.Discovery"> <Name> CSP customer services Discovery</Name> <Description>Discovers the managed services for each CSP customer</Description> </DisplayString> </DisplayStrings> <KnowledgeArticles></KnowledgeArticles> </LanguagePack> </LanguagePacks> </ManagementPackFragment>
Discovery script
param($sourceId, $managedEntityId, $computerName, $QueryUser, $QueryPwd, $ClientID, $TenantID) $starttime = get-date #Create Discovery Property Bag $api = new-object -comObject 'MOM.ScriptAPI' $discoveryData = $api.CreateDiscoveryData(0, $SourceId, $ManagedEntityId) $api.LogScriptEvent("GetCSPCustomers.ps1", 7001, 0, "Discovery Started. Trying to get data from CSP $TenantID as $QueryUser and ClientID: $ClientID") $tenantId = $TenantID $client_id = $ClientID $username = $QueryUser $password = Convertto-securestring $QueryPwd -asplaintext -force $creds = New-Object System.Management.Automation.PSCredential ($username, $password) $PartnerCenterPreFix = "https://api.partnercenter.microsoft.com/v1.0" $ErrorActionPreference = "stop" #AUTHENTICATE AGAINST THE PARTNER CENTER #Using app + user method we get an CSP authentication token function Get-PCAppUserAuthenticationBearer { <# .SYNOPSIS Function to retrieve App+User bearer token from Microsoft CSP API .DESCRIPTION This function connects to Azure AD to generate an oAuth token. Aquired token is then used against the partner center REST API to generate a App+User jwt token. https://api.partnercenter.microsoft.com/generatetoken You can read more about the authentication method here: https://msdn.microsoft.com/en-us/library/partnercenter/mt634709.aspx .PARAMETER ClientID The ClientID of the application used for authentication against Azure AD. .PARAMETER TenantId The TenantId of the Azure AD that you wish to authenticate against. Ie: test.onmicrosoft.com .PARAMETER Credential Pass a Powershell credential object or type in username and password .EXAMPLE Get-PCAppUserAuthenticationBearer -TenantID https://test.onmicrosoft.com -ClientID <Native App GUID> -username <[email protected]> -password <password> Returns a object containing the response from azure ad and a generated CSP bearer. Use the CSP bearer for further authenticating against the CSP API's and AAD token for reference .NOTES Version 1.0 Martin Ehrnst September 2017 #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$TenantID, [Parameter(Mandatory = $true)] [string]$ClientID, [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential]$Credential ) #clear error variable $error.clear() $ErrorActionPreference = "Stop" $username = $Credential.UserName $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(($Credential.Password)) $StringPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) #try to access azure ad to generate a token try { $loginurl = "https://login.windows.net/$tenantId/oauth2/token" $params = @{resource = "https://api.partnercenter.microsoft.com"; grant_type = "password"; client_id = $ClientId; username = $username; password = $StringPassword; scope = "openid"} $res = Invoke-RestMethod -Uri $loginurl -Method POST -Body $params $oAuth = "Bearer " + $res.access_token } catch { write-error -message "$error" } try { $CSPAuthHeader = @{ "Content-Type" = "application/x-www-form-urlencoded" "Authorization" = $oAuth } $CspAuthBody = "grant_type=jwt_token" $CSPAppUserToken = (Invoke-restmethod -uri 'https://api.partnercenter.microsoft.com/generatetoken' -Method Post -Body $CspAuthBody -Headers $CSPAuthHeader).access_token } catch { write-error -message "$error" } $CspBearer = "Bearer " + $CSPAppUserToken $Tokens = @{ "AzureAd" = $res "CSPBearer" = $CspBearer } $tokens } $Token = (Get-PCAppUserAuthenticationBearer -TenantID $tenantId -ClientID $client_id -Credential $creds -Verbose).CSPBearer $CSPheaders = @{ "Authorization" = $Token "Content-Type" = "text/json" } #GET ALL CUSTOMERS FROM OUR CSP PORTAL #Only properties needed are selected. $customerUri = $PartnerCenterPreFix + "/customers" try { $Customers = (Invoke-RestMethod -Uri $customerUri -Method Get -Headers $CSPheaders).items | Select-Object id, @{N = 'domain'; E = {$_.companyProfile.domain}}, @{N = 'companyName'; E = {$_.companyProfile.companyName}} } catch { $api.LogScriptEvent("GetCSPCustomers.ps1", 7005, 0, "Failed to retrieve CSP Customers from API $_") } #Loop through the customers and add them as instances. if ($Customers.count -gt "0") { $Count = $Customers.count $api.LogScriptEvent("GetCSPCustomers.ps1", 7002, 0, "Found $count Customers") foreach ($customer in $customers) { $Instance = $null $CompanyName = $Customer.companyName #Create a class instace $instance = $discoveryData.CreateClassInstance("$MPElement[Name='Office365.CSPCustomer.Class']$") #add class properties $instance.AddProperty("$MPElement[Name='Office365.CSPCustomer.Class']/CustomerName$", $CompanyName) $instance.AddProperty("$MPElement[Name='Office365.CSPCustomer.Class']/URL$", $customer.domain) $instance.AddProperty("$MPElement[Name='Office365.CSPCustomer.Class']/CSPID$", $customer.id) #add entity $instance.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $CompanyName + " (CSP Customer)") $instance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $computerName) #write data $api.LogScriptEvent("GetCSPCustomers.ps1", 7003, 0, "Adding $CompanyName") $discoveryData.AddInstance($instance) } } #Log script execution time $EndTime = Get-Date $ScriptTime = ($EndTime - $StartTime).TotalSeconds $api.LogScriptEvent("GetCSPCustomers.ps1", 7004, 0, "Discovery Ended - execution time $scripttime") #Return data $discoveryData