Sean already did Spark! (facepalm). Implemented Sean's Spark! into new get-pc

This commit is contained in:
Zachary Gorman 2024-08-07 11:33:25 -07:00
parent f3e8186b1c
commit 98a9474e11
13 changed files with 2145 additions and 293 deletions

View file

@ -5,8 +5,8 @@ function Get-PCBatchInvoke {
[string[]] [string[]]
$Computers $Computers
) )
$SparkEnabled = Get-SparkEnabled $Tenant = (Connect-ISM)[1]
if ($SparkEnabled) { Connect-ISM } $Headers = (Connect-ISM)[0]
#Region Script Block #Region Script Block
$sblock = { $sblock = {
Write-Progress -Activity "Retrieving data from online computers" -Status $Env:COMPUTERNAME -PercentComplete 10 Write-Progress -Activity "Retrieving data from online computers" -Status $Env:COMPUTERNAME -PercentComplete 10
@ -302,34 +302,32 @@ function Get-PCBatchInvoke {
Default {$chassisType = "Unknown Model/Chassis"} Default {$chassisType = "Unknown Model/Chassis"}
} }
if (${using:SparkEnabled}) { $uri = "${using:Tenant}/api/odata/businessobject/cis`?`$filter=Name eq '$ENV:COMPUTERNAME'&`$top=1&`$skip=0"
$uri = "${using:SparkURL}/api/odata/businessobject/CIs`?`$filter=Name+eq+%27$($Env:COMPUTERNAME)%27"
try { try {
$Query = Invoke-RestMethod -Method GET -uri $uri -headers ${using:SparkHeaders} $Query = Invoke-RestMethod -Method GET -uri $uri -headers ${using:Headers}
} catch { } catch {
$ExceptionErrors += $_.Exception.Message Write-Host $_.Exception.Message
} }
$cmdbData = $Query.Value $cmdbData = $Query.Value
if ($cmdbData.SHS_IsException -eq 'True') { $LocationConstructors = @(
Write-host "***NOTICE: $($Env:COMPUTERNAME) is a Device Exception computer. Please check CMDB/Asset Mgmt prior to supporting this workstation. ***" -BackgroundColor Black -ForegroundColor Yellow "SHS_AssetLocality",
if($cmdb.SHS_IsVendorPC -eq 'True'){ "ivnt_Location",
$vendor = "Yes | Non-standard SHS Image/Hardware" "SHS_Floor",
} "SHS_Department",
else{ "SHS_LocationDetails"
$vendor = "No | Standard SHS Hardware" )
}
$delInfo = [PSCustomObject]@{ $LocationData = Foreach($Loc in $LocationConstructors){
Contact = $cmdbData.SHS_ExceptionContact
Vendor = $vendor if ($Loc -eq 'SHS_Floor'){
Description = $cmdbData.AssignedDescription $(if ($cmdbData.$Loc -match '-'){$cmdbData.$Loc.split('-')[-1] + " Floor"} else{$cmdbData.$Loc})
} elseif (![string]::IsNullOrEmpty($cmdbData.$Loc)){
$cmdbData.$Loc
} }
} }
$locationData = $cmdbData.SHS_Floor + ' - ' + $cmdbData.SHS_Department + ' - ' + $cmdbData.SHS_LocationDetails $LocationData = $LocationData -join ' | '
}
Write-Progress -Activity "Retrieving data from online computers" -Status $Env:COMPUTERNAME -PercentComplete 90 Write-Progress -Activity "Retrieving data from online computers" -Status $Env:COMPUTERNAME -PercentComplete 90
#Output #Output
@ -358,13 +356,12 @@ function Get-PCBatchInvoke {
$obj | Add-Member -MemberType NoteProperty -Name 'TPM Status' -Value "$tpmStatus" $obj | Add-Member -MemberType NoteProperty -Name 'TPM Status' -Value "$tpmStatus"
$obj | Add-Member -MemberType NoteProperty -Name 'MBAM GPO' -Value "$gpostatus" $obj | Add-Member -MemberType NoteProperty -Name 'MBAM GPO' -Value "$gpostatus"
$obj | Add-Member -MemberType NoteProperty -Name 'Printers' -Value "$printers" $obj | Add-Member -MemberType NoteProperty -Name 'Printers' -Value "$printers"
if (${using:SparkEnabled}) { $obj | Add-Member -MemberType NoteProperty -Name 'CMDB Location' -Value "$LocationData"
$obj | Add-Member -MemberType NoteProperty -Name 'CMDB Location' -Value "$locationData" if($cmdbData.SHS_IsException -eq 'True'){
} Write-host "***NOTICE: $ENV:COMPUTERNAME is a Device Exception computer. Please check CMDB/Asset Mgmt prior to supporting this workstation. ***" -BackgroundColor Black -ForegroundColor Yellow
if ($delInfo) { $obj | Add-Member -MemberType NoteProperty -Name 'DEL Owner' -Value $cmdbData.SHS_ExceptionContact
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Owner' -Value $delInfo.Contact $obj | Add-Member -MemberType NoteProperty -Name 'DEL Vendor PC' -Value $cmdbData.SHS_IsVendorPC
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Vendor PC' -Value $delInfo.Vendor $obj | Add-Member -MemberType NoteProperty -Name 'DEL Description' -Value $cmdbData.SHS_ExceptionNotes
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Description' -Value $delInfo.Description
} }
return $obj return $obj
@ -387,17 +384,16 @@ function Get-PCBatchInvoke {
} }
BatchInvokesProgressBar -stage 2 BatchInvokesProgressBar -stage 2
$jobs = Invoke-Command -ScriptBlock $sblock -ComputerName $OnlineComputers -SessionOption (New-PSSessionOption -NoMachineProfile -OpenTimeout 45000) -AsJob $jobs = Invoke-Command -ScriptBlock $sblock -ComputerName $OnlineComputers -SessionOption (New-PSSessionOption -NoMachineProfile -OpenTimeout 45000) -AsJob
BatchInvokesProgressBar -stage 3
if($OfflineComputers.count -gt 0){ if($OfflineComputers.count -gt 0){
foreach($computer in $OfflineComputers){ foreach($computer in $OfflineComputers){
$jobs += Start-Job -ScriptBlock ${function:SCCMQueryBlock} -ArgumentList $computer $jobs += Start-Job -ScriptBlock ${function:SCCMQueryBlock} -ArgumentList $computer
} }
} }
BatchInvokesProgressBar -stage 4
$output += $jobs | Receive-Job -Wait -AutoRemoveJob | Select-Object * -ExcludeProperty RunspaceId, PSComputerName, PSShowComputerName $output += $jobs | Receive-Job -Wait -AutoRemoveJob | Select-Object * -ExcludeProperty RunspaceId, PSComputerName, PSShowComputerName
BatchInvokesProgressBar -stage 3
$itemIndex = 0 $itemIndex = 0
$contactedhosts = $output.Hostname $contactedhosts = $output.Hostname
BatchInvokesProgressBar -stage 5 BatchInvokesProgressBar -stage 4
$missedhosts = $OnlineComputers | Where-Object -FilterScript {$_ -notin $contactedhosts} $missedhosts = $OnlineComputers | Where-Object -FilterScript {$_ -notin $contactedhosts}
if($missedhosts.count -gt 0){ if($missedhosts.count -gt 0){
foreach($computer in $missedhosts){ foreach($computer in $missedhosts){
@ -446,7 +442,6 @@ function BatchInvokesProgressBar {
switch ($stage) { switch ($stage) {
1 { Write-Progress -Activity "Connecting to computers" -Status "$item ($currentItemIndex/$TotalItems)" -PercentComplete (($currentItemIndex/$TotalItems) * 100)} 1 { Write-Progress -Activity "Connecting to computers" -Status "$item ($currentItemIndex/$TotalItems)" -PercentComplete (($currentItemIndex/$TotalItems) * 100)}
2 { Write-Progress -Activity "Spinning up jobs" -PercentComplete ((20/100) * 100)} 2 { Write-Progress -Activity "Spinning up jobs" -PercentComplete ((20/100) * 100)}
4 { Write-Progress -Activity "Querying SCCM for offline computers" -PercentComplete ((30/100) * 100)}
3 { Write-Progress -Activity "Awaiting Jobs" -PercentComplete ((60/100)*100)} 3 { Write-Progress -Activity "Awaiting Jobs" -PercentComplete ((60/100)*100)}
4 { Write-Progress -Activity "Querying SCCM for missed computers" -PercentComplete ((75/100) * 100)} 4 { Write-Progress -Activity "Querying SCCM for missed computers" -PercentComplete ((75/100) * 100)}
Default {} Default {}

206
Private/Connect-ISM.ps1 Normal file
View file

@ -0,0 +1,206 @@
Function Connect-ISM {
<#
.SYNOPSIS
Primary authentication function leveraged by the module to connect to the Ivanti Service Manager API.
.DESCRIPTION
rimary authentication function leveraged by the module to connect to the Ivanti Service Manager API. Supports use of an API Key or SessionID authentication.
PRD = Production
STG = Staging
UAT = User Acceptance Testing
.PARAMETER -Environment
The ISM Environment you wish to connect to. This is a validate set containing "PRD", "UAT", "STG" environments.
.PARAMETER -TenantPrefix
The ISM URL prefix for the Tenant.
.PARAMETER -AuthType
Parameter that defines what type of authentication to use. APIKey requires procuring an API Key from the ITSM Admins and is primarily relegated for use by administrators and unattended scripts.
SessionID will prompt the user for Spark credentials and attempt to authenticate them directly. The default Role in the module is set for "ISAnalyst" but can be adjusted in the function.
.PARAMETER -ConnectionTest
Switch that when included will Invoke a WebRequest against the URL of the environment chosen. StatusDescription = OK will be returned on success.
.PARAMETER -AuthTypeCheck
Hidden parameter primarily intended for use internally by the module. This simply returns the value of AuthType and doesn't output any headers or make any API calls at all.
.INPUTS
A valid string.
.OUTPUTS
Returns the Tenant URI and the authorization headers necessary to make REST API calls to Ivanti Service Manager.
.NOTES
Version: 1.2
Author: Sean Carlton
Creation Date: 04/26/2023
Purpose/Change: Added AA_API_Key variable and check to leverage Get-AutomationPSCredential when $PSPrivateMetaData is not null. This variable is populated when a script is executing from Azure Automation (Cloud and Hybrid Worker), but otherwise is null.
Version: 1.1
Author: Sean Carlton
Creation Date: 10/06/2022
Purpose/Change: Added initial SessionID support. To leverage this option requires a local login in Spark which most users do not have. A request has been submitted with Ivanti to determine if we can leverage OIDC auth instead. If so, the code will be in place to allow use of ISMTools without an API Key, using your own credentials for authentication to the API. Added the hidden -ConfigCheck switch which will return the Connect-ISM configuration currently in use.
Version: 1.0
Author: Sean Carlton
Creation Date: 08/16/2022
Purpose/Change: Initial script development
.EXAMPLE
The below example demonstrates how to define the ISM/Spark environment you wish to connect to upon initial import. If the -ArgumentList parameter is not provided when Import-Module is ran, then the $Environment variable configured in Connect-ISM will be used to determine which environment to connect to.
Import-Module 'ISMTools' -ArgumentList 'PRD'
.EXAMPLE
(Connect-ISM)[0] will return the authorization headers.
(Connect-ISM)[1] will return the Tenant URL.
(Connect-ISM)[2] will return the Authentication Type.
.EXAMPLE
The -ConnectionTest switch will invoke a WebRequest against the Tenant URL the function is configured to connect to. It can be leveraged to check that your connection to ISM/Spark is valid. It returns all of the other properties but includes the StatusDescription of the Invoke-WebRequest call as well.
Connect-ISM -ConnectionTest
If Statement example to confirm you're connected to Spark before continuing:
if ((Connect-ISM -ConnectionTest)[-1].StatusDescription -eq "OK"){
Write-Host "Connected to Spark!"
} else {
Write-Warning "Failed to connect to Spark!"
Exit
}
.EXAMPLE
The -ConfigCheck switch will return the current configuration of the module for reference.
Connect-ISM -ConfigCheck
#>
[CmdletBinding()]
param (
[Parameter()]
[ValidateSet("STG", "UAT", "PRD")]
$Environment = $(if ($Module_Environment){
$Module_Environment
}else{
## Define the Default Environment here. This will be used when no environment is passed by Import-Module
"PRD"
}),
[Parameter()]
[ValidateSet("APIKey", "SessionID")]
[string]$AuthType = "APIKey",
[Parameter()]
## ServiceDeskAnalyst
## ISAnalyst
## Admin
## DesktopTechnician
[string]$Role = "ISAnalyst",
[Parameter()]
[string]$TenantPrefix = "samaritanhealth-amc",
[Parameter()]
[switch]$ConnectionTest,
[Parameter(DontShow)]
[switch]$ConfigCheck
)
BEGIN {
##Initialize the Headers Hashtable.
$Headers = @{
"Content-Type" = "application/json"
"Authorization" = $null
"Accept" = "*/*"
"Accept-Encoding" = "gzip, deflate, br"
}
## If $PSPrivateMetaData is NOT null then this is running from an Azure Runbook/via Hybrid Worker. We'll attempt to pull the API key from the Credential Store of the automation account directly in that scenario.
$Azure_Execution = ($null -ne $PSPrivateMetadata)
if ($Azure_Execution){
$Cred_Obj = Get-AutomationPSCredential -Name "ISM $Environment API Key"
if ($Cred_Obj){
$AA_API_Key = (New-Object PSCredential $Cred_Obj.Username,$Cred_Obj.Password).GetNetworkCredential().Password;
}
}
## Initialize the URL and API_Key based on $Environment selection.
## If you don't have acess to the API Key for the environment you need, please reach out to the ITSM Team to request access.
Switch ($Environment){
"STG" {
$API_Key = if($AA_API_Key){$AA_API_Key}else{''};
$URL = "https://$TenantPrefix-$Environment.ivanticloud.com"
}
"UAT" {
$API_Key = if($AA_API_Key){$AA_API_Key}else{''};
$URL = "https://$TenantPrefix-$Environment.ivanticloud.com"
}
"PRD" {
$API_Key = if($AA_API_Key){$AA_API_Key}else{'EB68123D62F8489295C807353C92D75B'};
$URL = "https://$TenantPrefix.ivanticloud.com"
}
}#END $ENVIRONMENT SWITCH
}#END BEGIN BLOCK
PROCESS {
Switch ($AuthType){
"APIKey" {
## Add the API_Key to the Headers
$Headers["Authorization"] = "rest_api_key=$API_Key"
}
"SessionID" {
## Prompt for Network Credentials if we don't have a valid SessionID/Token already stored.
if (!$ISMToolsModuleSessionID.SessionID){
$SessionIDCreds = Get-Credential -User $ENV:Username -Message "Enter your network password to authenticate into Spark with the $Role role."
$Body = @{
"Tenant" = $URL.Split('/')[-1]
"Username" = $SessionIDCreds.Username
"Password" = $SessionIDCreds.GetNetworkCredential().Password
"Role" = $Role
}
$JSONBody = $Body | ConvertTo-Json
if ($SessionIDCreds.GetNetworkCredential().Password){
try {
$URI = "$URL/api/rest/authentication/login"
$SessionID = Invoke-RestMethod -uri $URI -Method Post -Body $JSONBody -headers $Headers
}
catch {$_.Exception.Message}
}
if ($SessionID -match "#"){
$ISMToolsModuleSessionID.SessionID = $SessionID
} else {
Write-Host "Failed to authenticate with role $($Body.Role) with the provided credentials! Please check the credentials and role configured in the Connect-ISM function and try again." -ForegroundColor yellow
}
$SessionIDCreds = $null
}#End If No ISM_Tools_Module_Session_ID_Token
## Add the SessionID to the Headers
$Headers["Authorization"] = $ISMToolsModuleSessionID.SessionID
}
}#END AUTHTYPE SWITCH
## Run the ConnectionTest if -ConnectionTest was passed.
if ($ConnectionTest){
$TestConnection = Invoke-WebRequest $URL -UseBasicParsing | Select-Object StatusDescription
}
}#END PROCESS BLOCK
END {
if ($ConfigCheck){
return $Environment, $AuthType, $Role, $TenantPrefix, $URL, $API_Key
} else {
return $Headers, $URL, $AuthType, $TestConnection
}
}#END END-BLOCK
}#End Connect-ISM Function

View file

@ -0,0 +1,254 @@
Function Find-ISMBusinessObject {
<#
.SYNOPSIS
Gets all records of a specified business object OR one particular record when a -RecID is provided.
.DESCRIPTION
Gets all records of a specified business object OR one particular record when a -RecID is provided. Additionally can retrieve metadata for any business object.
.PARAMETER -BusinessObject
The Business Object you are interacting with. (Incidents, CIs, CI__ActiveDirectorys, ServiceReqs, Locations, Employees, Manufacturers, StandardUserTeams, Problems, Changes, etc...)
.PARAMETER -RecID
The Record ID (RecID) of the specific record you wish to retrieve from the business object.
.PARAMETER -Top
Optional parameter that can be used to specify the number of records you'd like back from the business object. If the supplied number is greater than the total number of records or the -Top parameter is not specified, all records will be returned.
.PARAMETER -Metadata
Switch that results in the function returning the Business Object metadata as opposed to any of its records. Metadata contains lots of useful information about the business object such as the fields and quick actions that are associated with that business object.
.PARAMETER -PropertyList
Optional parameter that will query the supplied -BusinessObject metadata and return all of its fields/properties.
.PARAMETER -PropertyMatch
Optional parameter that allows for a match search against the -PropertyList. Useful for locating specific field names/properties of the business object.
.PARAMETER -DetailedOutput
Optional hidden parameter that includes some additional output during querying of the Business Object. Primarily used for debugging.
.INPUTS
Business Object and optionally a -RecID.
.OUTPUTS
The business object(s) are returned.
.NOTES
Version: 1.0
Author: Sean Carlton
Creation Date: 08/16/2022
Purpose/Change: Initial script development
.EXAMPLE
Get-ISMBusinessObject -BusinessObject incidents
=======
This example demonstrates getting all incident records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject incidents -RecID "5788C7AB6E1E44AD8464FED18A510609"
=======
This example demonstrates getting a specific incident record based on its RecID.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject ci__activedirectorys -RecID "5788C7AB6E1E44AD8464FED18A510609"
=======
This example demonstrates getting all records of the CI__ActiveDirectorys extended business object. Extended business objects are formatted with two underscores(__) separating the parent business object from the child business object.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject cis
=======
This example demonstrates retrieving all ci records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject cis -top 3
=======
This example demonstrates retrieving the top 3 ci records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -metadata
=======
This example demonstrates querying the employees business object for its metadata.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -PropertyMatch "email"
=======
This example demonstrates querying the employees business object for any fields/properties that match "email". This is useful for quickly locating specific fields you need to interact with.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -PropertyList
=======
This example demonstrates querying the employees business object metadata for all of its associated fields/properties. A list of all fields will be returned.
=======
#>
[CmdletBinding(DefaultParameterSetName = 'BusinessObj')]
param (
[Alias("BO")]
[Parameter(Mandatory = $true,
HelpMessage = 'Business Object to query for (Incidents, ServiceReqs, CIs, Changes, etc...)',
Position = 0)]
[string]$BusinessObject,
[Parameter()]
[string]$SearchQuery,
# [Parameter()]
# [string]$Top,
[Parameter(DontShow)]
[switch]$DetailedOutput,
### API Connection Parameters ###
[Parameter(HelpMessage = 'Tenant URL', DontShow)]
[string]$Tenant = (Connect-ISM)[1],
[Parameter(HelpMessage = 'Authorization Header', DontShow)]
[hashtable]$Headers = (Connect-ISM)[0]
)
# #Default the Top value to 100. (Maximum allowed record query per API call.)
# if (!$Top -or ($Top -gt 100)){
# $InitialTop = "100"
# } else {
# $InitialTop = $Top
# }
# $URI = "$Tenant/api/odata/businessobject/$BusinessObject`?`$top=$InitialTop`$search=$SearchQuery"
$URI = "$Tenant/api/odata/businessobject/$BusinessObject`?`$search=$SearchQuery"
#### FULLTEXT SEARCH
# ##TESTING
# $URI = "$Tenant/api/rest/search/fulltext"
# $ParamHash = @{
# "Text" = $SearchQuery
# "ObjectType" = $BusinessObject
# "Top" = $InitialTop
# "Field" = "SHS_LocationDetails"
# # "Skip" = 0
# }
# $Query = Invoke-RestMethod -Method POST -uri $URI -headers $Headers -Body ($ParamHash | ConvertTo-JSON)
# $Query.Data
# ##TESTING
try {
$Query = Invoke-RestMethod -Method GET -uri $URI -headers $Headers
if (!$Query){
Write-Host "No results returned for the $BusinessObject Business Object!" -ForegroundColor yellow
} elseif ($Query.Edmx){
$Query.edmx.DataServices.schema | Add-Member -Value $BusinessObject -MemberType NoteProperty -Name "QueriedBusinessObject" -Force
#Return the DataServices.schema of the object
$Results = $Query.edmx.DataServices.schema
} elseif ($Query.Value){
if ($DetailedOutput){
Write-Host "The $BusinessObject business object has $($Query.'@odata.count') total records."
}
$Results = @()
if (($Query.Value | Measure-Object).count -eq $Top -and ![string]::isnullorempty($Top)){
$Query.'@odata.count' = $Top
$Results = $Query.Value
} elseif (($Query.Value | Measure-Object).count -gt $Top -and ![string]::isnullorempty($Top)){
$Query.'@odata.count' = $Top
$Results = $Query.Value | Select-Object -First $Top
} elseif (($Query.Value | Measure-Object).count -lt $Top -and ![string]::isnullorempty($Top)){
if (!$Top -gt $Query.'@odata.count'){
$Query.'@odata.count' = $Top
}
$Results += $Query.Value
} else {
$Results += $Query.Value
}
if ($Results.Count -ne $Query.'@odata.count'){
$ExitLoop = $false
Do {
$Skip = $Results.Count
$URI = "$Tenant/api/odata/businessobject/$BusinessObject`?`$top=100&`$skip=$Skip`$search=$SearchQuery"
$SkipQuery = Invoke-RestMethod -Method GET -uri $URI -headers $Headers
if ($SkipQuery){
$Results += $SkipQuery.Value
if ($Results.count -gt $Top -and ![string]::isnullorempty($Top)){
$Results = $Results | Select-Object -First $Top
$ExitLoop = $true
}
} else {
write-warning "Failed to query for $BusinessObject! (Skip: $Skip | Total: $($Query.'@odata.count')) "
$ExitLoop = $true
}
} until (($Results.Count -ge $Query.'@odata.count') -or $ExitLoop)
}
} else {
$Results = $Query
}
#Friendly little helper loop to parse employee business object MemberOf HTML fields into a proper array.
if ($BusinessObject -eq "employees" -and (!$Metadata)){
Foreach ($Employee in $Results){
$Employee | Add-Member -MemberType NoteProperty -Value @() -Name "SHS_MemberOfParsed" -force
if ($Employee.SHS_MemberOf){
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOf.replace("<br>","%").split("%").trim()
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOfParsed | Sort-Object
}
}
}
if ($PropertyList -and $Results -or $PropertyMatch -and $Results){
if ($Results.EntityType.count){
$BO_Properties = $Results.EntityType[-1].Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
} else {
$BO_Properties = $Results.EntityType.Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
}
if ($PropertyMatch){
$BO_Properties = $BO_Properties | Where-Object {$_.Name -match $PropertyMatch}
}
return $BO_Properties
} else {
return $Results
}
}
catch {
write-warning "Failed querying for $BusinessObject!"
}
}#END FUNCTION
New-Alias -Name Find-ISMBO -Value Find-ISMBusinessObject -Force

View file

@ -3,31 +3,87 @@ function Get-CMDBFallback {
$comp $comp
) )
#$cmdbData = Get-LANDeskCMDBItem -name $comp ## $cmdbData = Get-LANDeskCMDBItem -name $comp
$cmdbData = Get-SparkCI $comp $cmdbData = Search-ISMBO -bo cis -filter "Name eq '$comp'" -RawFilter
if(!$cmdbData){
if($comp.Length -gt 5){
$asset = $comp[-5..-1] -join ""
## $cmdbData = Get-LANDeskCMDBItem -AssetTag $asset
$cmdbData = Search-ISMBO -bo cis -filter "AssetTag eq '$asset'" -RawFilter
if($cmdbData){
$comp = $cmdbData.values.Title
if(Test-Connection $comp){
$getpcData = get-pc $comp
return $getpcData
}
}
}
}
$status = $cmdbData.Status $status = $cmdbData.Status
if(!$status){ if(!$status){
$status = 'No CMDB/SCCM Record Located' $status = 'No CMDB/SCCM Record Located'
} } else{
else{
$status = $cmdbData.Status + ' (CMDB Data)' $status = $cmdbData.Status + ' (CMDB Data)'
} }
$locationData = $cmdbData.SHS_Floor + ' - ' + $cmdbData.SHS_Department + ' - ' + $cmdbData.SHS_LocationDetails $LocationConstructors = @(
"SHS_AssetLocality",
"ivnt_Location",
"SHS_Floor",
"SHS_Department",
"SHS_LocationDetails"
)
$phoneNumber = $cmdbData.LoginName $LocationData = Foreach($Loc in $LocationConstructors){
if ($Loc -eq 'SHS_Floor'){
$(if ($cmdbData.$Loc -match '-'){$cmdbData.$Loc.split('-')[-1] + " Floor"} else{$cmdbData.$Loc})
} elseif (![string]::IsNullOrEmpty($cmdbData.$Loc)){
$cmdbData.$Loc
}
}
$LocationData = $LocationData -join ' | '
# $locationData = $cmdbData.SHS_AssetLocality + " | " + $cmdbData.ivnt_Location + " | " + $(if ($cmdbData.SHS_Floor -match '-'){$cmdbData.SHS_Floor.split('-')[-1] + " Floor"}) + " | " + $cmdbData.SHS_Department + " | " + $cmdbData.SHS_LocationDetails
# if($cmdbData.values._SHSLocation3.Length -gt $cmdbData.values._SHSCalcLocationString.Length){
# $locationData = $cmdbData.values._SHSLocation3
# }
# else{
# $locationData = $cmdbData.values._SHSCalcLocationString
# }
if($cmdbData.CIType -eq 'MobileDevice'){ if($cmdbData.CIType -eq 'MobileDevice'){
$cmdbData = Get-ISMBO -bo ci__mobiledevicess -RecID $cmdbData.RecId
# $props = [Ordered]@{
# Hostname = $cmdbData.Title
# 'MAC' = $cmdbData.values._SHSMACAddress
# Model = $cmdbData.values._Model + ' (' + $cmdbData.Values._SHSChasisRef + ')'
# 'OS' = $cmdbData.Values._SHSOperatingSystem
# 'Asset Tag' = $cmdbData.values._SHSAssetTag
# 'Service Tag' = $cmdbData.values._SerialNumber
# 'MDM Platform' = $cmdbData.values._SHSMDMPlatform
# 'Phone Number' = $cmdbData.values._SHSPhoneNumber
# 'Cellular Carrier' = $cmdbData.values._SHSCellularCarrier
# 'Cellular Voice' = $cmdbData.values._SHSCellularVoice
# 'Cellular Data' = $cmdbData.values._SHSCellularData
# 'CMDB Location' = $locationData
# }
$props = [Ordered]@{ $props = [Ordered]@{
Hostname = $cmdbData.Name Hostname = $cmdbData.Name
'MAC' = $cmdbData.MACAddress 'MAC' = $cmdbData.MACAddress
Model = $cmdbData.Model + ' (' + $cmdbData.ChassisType + ')' Model = $cmdbData.Model + ' (' + $cmdbData.ivnt_assetsubtype + ')'
'OS' = $cmdbData.OperatingSystem 'OS' = $cmdbData.SHS_AssignedOperatingSystem + " " + $cmdbData.OSMajorVersion
'Asset Tag' = $cmdbData.AssetTag 'Asset Tag' = $cmdbData.AssetTag
'Service Tag' = $cmdbData.SerialNumber 'Service Tag' = $cmdbData.SerialNumber
'MDM Platform' = $cmdbData.SHS_MdmPlatform 'MDM Platform' = $cmdbData.SHS_MdmPlatform
'Phone Number' = $cmdbData.PhoneNumber #TODO fix this, idk why Spark! doesn't return this 'MDM Config' = $cmdbData.SHS_ConfigProfile
'MDM Last Seen' = $cmdbData.SHS_LastSeen
'Phone Number' = $cmdbData.PhoneNumber
'Cellular Carrier' = $cmdbData.SHS_Carrier 'Cellular Carrier' = $cmdbData.SHS_Carrier
'Cellular Voice' = $cmdbData.SHS_IsCellularVoice 'Cellular Voice' = $cmdbData.SHS_IsCellularVoice
'Cellular Data' = $cmdbData.SHS_IsCellularData 'Cellular Data' = $cmdbData.SHS_IsCellularData
@ -37,21 +93,53 @@ function Get-CMDBFallback {
$obj = New-Object -TypeName PSObject -Property $props $obj = New-Object -TypeName PSObject -Property $props
} }
else{ else{
# $props = [Ordered]@{
# Hostname = "$comp"
# Status = $status
# 'Current User' = "Not Available"
# 'Last User(s)' = $null
# 'IP | MAC' = $cmdbData.values._IPAddress + " | " + $cmdbData.values._SHSMACAddress
# Model = $cmdbData.values._Model + ' (' + $cmdbData.Values._SHSChasisRef + ')'
# 'OS' = $cmdbData.Values._SHSOperatingSystem
# 'OS Build' = $null
# 'BIOS Ver' = $null
# Encryption = $null
# 'Free Space' = $cmdbData.Values._AvailableDiskSpace + ' GB / ' + $cmdbData.Values._HardDiskSize + ' GB'
# RAM = $cmdbData.Values._RAM + " GB "
# 'SSO Client' = "Not Available"
# 'Kiosk Role' = "Not Available"
# 'Asset Tag' = $cmdbData.values._SHSAssetTag
# 'Service Tag' = $cmdbData.values._SerialNumber
# 'Last Reboot' = $null
# Printers = $null
# 'CMDB Location' = $locationData
# }
if ($cmdbData.CIType -eq "Computer"){
$cmdbData = Get-ISMBO -BO ci__computers -recid $cmdbData.Recid
$memoryData = Search-ISMBO -bo frs_CIComponent__memorys -Filter "ParentLink_RecId eq '$($cmdbData.RecId)'" -RawFilter
$diskData = Search-ISMBO -bo frs_cicomponent__logicalstorages -Filter "ParentLink_RecId eq '$($cmdbdata.recid)'" -Rawfilter
if ($memoryData){
$MemoryTotal = ($Memorydata.Memorysize | measure-object -sum).sum
}
}
$props = [Ordered]@{ $props = [Ordered]@{
Hostname = "$comp" Hostname = "$comp"
Status = $status Status = $status
'Current User' = "Not Available" 'Current User' = "Not Available"
'Last User(s)' = $null 'Last User(s)' = $cmdbData.LoginName
'IP | MAC' = $cmdbData.IPAddress + " | " + $cmdbData.MACAddress 'IP | MAC' = $cmdbData.IPAddress + " | " + $cmdbData.MACAddress
Model = $cmdbData.Model + ' (' + $cmdbData.ChassisType + ')' Model = $cmdbData.Model + ' (' + $cmdbData.ivnt_assetsubtype + ')'
'OS' = $cmdbData.OperatingSystem 'OS' = $cmdbData.OperatingSystem + " " + $cmdbData.OSMajorVersion
'OS Build' = $null 'OS Build' = $cmdbData.OSMajorVersion
'BIOS Ver' = $null 'BIOS Ver' = $cmdbData.BIOSVersion + " ($($cmdbData.BiosDate))"
Encryption = $null Encryption = $cmdbData.ivnt_EncryptionState
'Free Space' = $cmdbData.Values._AvailableDiskSpace + ' GB / ' + $cmdbData.Values._HardDiskSize + ' GB' 'Free Space' = $diskData.FreeSpace + ' GB / ' + $diskData.capacity + ' GB'
RAM = $cmdbData.Values._RAM + " GB " 'RAM' = $MemoryTotal+ " GB "
'SSO Client' = "Not Available" 'SSO Client' = "Not Available"
'Kiosk Role' = "Not Available" # 'Kiosk Role' = "Not Available"
'Asset Tag' = $cmdbData.AssetTag 'Asset Tag' = $cmdbData.AssetTag
'Service Tag' = $cmdbData.SerialNumber 'Service Tag' = $cmdbData.SerialNumber
'Last Reboot' = $null 'Last Reboot' = $null
@ -59,16 +147,52 @@ function Get-CMDBFallback {
'CMDB Location' = $locationData 'CMDB Location' = $locationData
} }
if ($cmdbData.SHS_IsKiosk){
$props.add("Kiosk Role", $cmdbdata.SHS_KioskRoles)
}
$obj = New-Object -TypeName PSObject -Property $props $obj = New-Object -TypeName PSObject -Property $props
} }
Write-Host "`n`nPulling cached CMDB data for $comp." -ForegroundColor Yellow Write-Host "`n`nPulling cached CMDB data for $comp." -ForegroundColor Yellow
Write-Host "Last CMDB Update: ",$cmdbData.values.LastUpdate -ForegroundColor Yellow Write-Host "Last CMDB Update: ",$cmdbData.LastModDateTime -ForegroundColor Yellow
if($cmdbData.SHS_IsException -eq 'True'){ if($cmdbData.SHS_IsException -eq 'True'){
$delInfo = Get-CMDBDELInfo $cmdbData ## $delInfo = Get-CMDBDELInfo $cmdbData
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Owner' -Value $delInfo.Contact $obj | Add-Member -MemberType NoteProperty -Name 'DEL Owner' -Value $cmdbData.SHS_ExceptionContact
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Vendor PC' -Value $delInfo.Vendor $obj | Add-Member -MemberType NoteProperty -Name 'DEL Vendor PC' -Value $cmdbData.SHS_IsVendorPC
$obj | Add-Member -MemberType NoteProperty -Name 'DEL Description' -Value $delInfo.Description $obj | Add-Member -MemberType NoteProperty -Name 'DEL Description' -Value $cmdbData.SHS_ExceptionNotes
} }
return $obj return $obj
} }
function Get-CMDBData {
[CmdletBinding()]
param (
[Parameter()]
[string]
$comp,
[string]
$asset
)
if($asset -match "\w \w"){
$asset = $asset -split ' '
$asset = $asset[0]
}
## $cmdb = Get-LANDeskCMDBItem -Name $comp
$cmdb = Search-ISMBO -bo cis -filter "Name eq '$comp'" -RawFilter
if ($null -eq $cmdb){
try {
## $cmdb = Get-LANDeskCMDBItem -AssetTag $asset
$cmdb = Search-ISMBO -bo cis -filter "AssetTag eq '$asset'" -RawFilter
} catch{ $cmdb = $null }
}
return $cmdb
}

View file

@ -3,6 +3,10 @@ function Get-Hostname ([string]$name) {
if ($name.Length -eq 5) { if ($name.Length -eq 5) {
$res = Get-AssetConversion $name $res = Get-AssetConversion $name
if ($res) { return $res,'' } if ($res) { return $res,'' }
try {
$cmdbData = Search-ISMBO -bo cis -filter "AssetTag eq '$name'" -RawFilter
} catch { $cmdbData = $null }
if ( $cmdbData ) { return $cmdbData.values.title, '' }
else { $errMsg += "$name Asset Tag not in SMBIOS or CMDB. " } else { $errMsg += "$name Asset Tag not in SMBIOS or CMDB. " }
} }
# Regex to match IP Address brought to you by https://stackoverflow.com/a/36760050 # Regex to match IP Address brought to you by https://stackoverflow.com/a/36760050

View file

@ -0,0 +1,284 @@
Function Get-ISMBusinessObject {
<#
.SYNOPSIS
Gets all records of a specified business object OR one particular record when a -RecID is provided.
.DESCRIPTION
Gets all records of a specified business object OR one particular record when a -RecID is provided. Additionally can retrieve metadata for any business object.
.PARAMETER -BusinessObject
The Business Object you are interacting with. (Incidents, CIs, CI__ActiveDirectorys, ServiceReqs, Locations, Employees, Manufacturers, StandardUserTeams, Problems, Changes, etc...)
.PARAMETER -RecID
The Record ID (RecID) of the specific record you wish to retrieve from the business object.
.PARAMETER -Top
Optional parameter that can be used to specify the number of records you'd like back from the business object. If the supplied number is greater than the total number of records or the -Top parameter is not specified, all records will be returned.
.PARAMETER -Metadata
Switch that results in the function returning the Business Object metadata as opposed to any of its records. Metadata contains lots of useful information about the business object such as the fields and quick actions that are associated with that business object.
.PARAMETER -PropertyList
Optional parameter that will query the supplied -BusinessObject metadata and return all of its fields/properties.
.PARAMETER -PropertyMatch
Optional parameter that allows for a match search against the -PropertyList. Useful for locating specific field names/properties of the business object.
.PARAMETER -DetailedOutput
Optional hidden parameter that includes some additional output during querying of the Business Object. Primarily used for debugging.
.INPUTS
Business Object and optionally a -RecID.
.OUTPUTS
The business object(s) are returned.
.NOTES
Version: 1.0
Author: Sean Carlton
Creation Date: 08/16/2022
Purpose/Change: Initial script development
.EXAMPLE
Get-ISMBusinessObject -BusinessObject incidents
=======
This example demonstrates getting all incident records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject incidents -RecID "5788C7AB6E1E44AD8464FED18A510609"
=======
This example demonstrates getting a specific incident record based on its RecID.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject ci__activedirectorys -RecID "5788C7AB6E1E44AD8464FED18A510609"
=======
This example demonstrates getting all records of the CI__ActiveDirectorys extended business object. Extended business objects are formatted with two underscores(__) separating the parent business object from the child business object.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject cis
=======
This example demonstrates retrieving all ci records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject cis -top 3
=======
This example demonstrates retrieving the top 3 ci records.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -metadata
=======
This example demonstrates querying the employees business object for its metadata.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -PropertyMatch "email"
=======
This example demonstrates querying the employees business object for any fields/properties that match "email". This is useful for quickly locating specific fields you need to interact with.
=======
.EXAMPLE
Get-ISMBusinessObject -BusinessObject employees -PropertyList
=======
This example demonstrates querying the employees business object metadata for all of its associated fields/properties. A list of all fields will be returned.
=======
#>
[CmdletBinding(DefaultParameterSetName = 'BusinessObj')]
param (
[Alias("BO")]
[Parameter(Mandatory = $true,
HelpMessage = 'Business Object to query for (Incidents, ServiceReqs, CIs, Changes, etc...)',
Position = 0)]
[Parameter(
ParameterSetName = 'BusinessObj')]
[Parameter(
ParameterSetName = 'RecID')]
[Parameter(
ParameterSetName = 'Metadata')]
[string]$BusinessObject,
[Parameter(
ParameterSetName = 'RecID')]
[string]$RecID,
[Parameter(
ParameterSetName = 'BusinessObj')]
[string]$Top,
[Parameter(
ParameterSetName = 'Metadata')]
[switch]$Metadata,
[Parameter(
ParameterSetName = 'Metadata')]
[string]$PropertyMatch,
[Parameter(
ParameterSetName = 'Metadata')]
[switch]$PropertyList,
[Parameter(
ParameterSetName = 'BusinessObj')]
[Parameter(
ParameterSetName = 'RecID')]
[Parameter(
ParameterSetName = 'Metadata')]
[Parameter(DontShow)]
[switch]$DetailedOutput,
### API Connection Parameters ###
[Parameter(HelpMessage = 'Tenant URL', DontShow)]
[string]$Tenant = (Connect-ISM)[1],
[Parameter(HelpMessage = 'Authorization Header', DontShow)]
[hashtable]$Headers = (Connect-ISM)[0]
)
switch ($PSCmdlet.ParameterSetName) {
'Metadata' {
$URI = "$Tenant/api/odata/$BusinessObject/`$metadata"
break
}
'RecId' {
$URI = "$Tenant/api/odata/businessobject/$BusinessObject('$RecID')"
break
}
"BusinessObj" {
If ($BusinessObject -match "."){
$BusinessObject = $BusinessObject.replace(".","__")
}
#Default the Top value to 100. (Maximum allowed record query per API call.)
if (!$Top -or ($Top -gt 100)){
$InitialTop = "100"
} else {
$InitialTop = $Top
}
$URI = "$Tenant/api/odata/businessobject/$BusinessObject`?`$top=$InitialTop"
break
}
}
try {
$Query = Invoke-RestMethod -Method GET -uri $URI -headers $Headers
if (!$Query){
Write-Host "No results returned for the $BusinessObject Business Object!" -ForegroundColor yellow
} elseif ($Query.Edmx){
$Query.edmx.DataServices.schema | Add-Member -Value $BusinessObject -MemberType NoteProperty -Name "QueriedBusinessObject" -Force
#Return the DataServices.schema of the object
$Results = $Query.edmx.DataServices.schema
} elseif ($Query.Value){
if ($DetailedOutput){
Write-Host "The $BusinessObject business object has $($Query.'@odata.count') total records."
}
$Results = @()
if (($Query.Value | Measure-Object).count -eq $Top -and ![string]::isnullorempty($Top)){
$Query.'@odata.count' = $Top
$Results = $Query.Value
} elseif (($Query.Value | Measure-Object).count -gt $Top -and ![string]::isnullorempty($Top)){
$Query.'@odata.count' = $Top
$Results = $Query.Value | Select-Object -First $Top
} elseif (($Query.Value | Measure-Object).count -lt $Top -and ![string]::isnullorempty($Top)){
if (!$Top -gt $Query.'@odata.count'){
$Query.'@odata.count' = $Top
}
$Results += $Query.Value
} else {
$Results += $Query.Value
}
if ($Results.Count -ne $Query.'@odata.count'){
$ExitLoop = $false
Do {
$Skip = $Results.Count
$URI = "$Tenant/api/odata/businessobject/$BusinessObject`?`$top=100&`$skip=$Skip"
$SkipQuery = Invoke-RestMethod -Method GET -uri $URI -headers $Headers
if ($SkipQuery){
$Results += $SkipQuery.Value
if ($Results.count -gt $Top -and ![string]::isnullorempty($Top)){
$Results = $Results | Select-Object -First $Top
$ExitLoop = $true
}
} else {
write-warning "Failed to query for $BusinessObject! (Skip: $Skip | Total: $($Query.'@odata.count')) "
$ExitLoop = $true
}
} until (($Results.Count -ge $Query.'@odata.count') -or $ExitLoop)
}
} else {
$Results = $Query
}
#Friendly little helper loop to parse employee business object MemberOf HTML fields into a proper array.
if ($BusinessObject -eq "employees" -and (!$Metadata)){
Foreach ($Employee in $Results){
$Employee | Add-Member -MemberType NoteProperty -Value @() -Name "SHS_MemberOfParsed" -force
if ($Employee.SHS_MemberOf){
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOf.replace("<br>","%").split("%").trim()
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOfParsed | Sort-Object
}
}
}
if ($PropertyList -and $Results -or $PropertyMatch -and $Results){
if ($Results.EntityType.count){
$BO_Properties = $Results.EntityType[-1].Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
} else {
$BO_Properties = $Results.EntityType.Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
}
if ($PropertyMatch){
$BO_Properties = $BO_Properties | Where-Object {$_.Name -match $PropertyMatch}
}
return $BO_Properties
} else {
return $Results
}
}
catch {
write-warning "Failed querying for $BusinessObject!"
}
}#END FUNCTION
New-Alias -Name Get-ISMBO -Value Get-ISMBusinessObject -Force

View file

@ -5,12 +5,16 @@ function Invoke-CMDBweblaunch {
} }
Write-Host "Querying CMDB..." Write-Host "Querying CMDB..."
try { $cmdbData = Get-LANDeskCMDBItem -Name $comp } catch { $cmdbData = $null} try { $cmdbData = Search-ISMBO -bo cis -filter "name eq '$comp'" -RawFilter } catch { $cmdbData = $null}
if($null -eq $cmdbData){ if($null -eq $cmdbData){
Write-Host "CMDB hostname mismatch" -ForegroundColor Yellow Write-Host "CMDB hostname mismatch" -ForegroundColor Yellow
Write-Host "Running Get-PC Lookup for asset tag" Write-Host "Running Get-PC Lookup for asset tag"
$getpcData = get-pc $comp $getpcData = get-pc $comp
try { $cmdbData = Get-LANDeskCMDBItem -AssetTag $getpcData.'Asset Tag'} catch{ $cmdbData = $null } try {
## $cmdbData = Get-LANDeskCMDBItem -AssetTag $getpcData.'Asset Tag'
$cmdbData = Search-ISMBO -bo cis -filter "assettag eq '$($getpcData.'Asset Tag')'" -RawFilter
} catch{ $cmdbData = $null }
if($null -eq $cmdbData){ if($null -eq $cmdbData){
Write-Warning "Unable to find record with assset tag in CMDB" Write-Warning "Unable to find record with assset tag in CMDB"
Write-Host "Unable to launch record page" -ForegroundColor Yellow Write-Host "Unable to launch record page" -ForegroundColor Yellow
@ -20,8 +24,10 @@ function Invoke-CMDBweblaunch {
Write-Host "CMDB record found - launching Landesk page in IE" Write-Host "CMDB record found - launching Landesk page in IE"
$uri = "https://shslandesk/WebAccess/wd/object/open.rails?class_name=_CMDBManagement.Call&key=" # $uri = "https://shslandesk/WebAccess/wd/object/open.rails?class_name=_CMDBManagement.Call&key="
$fulluri = $uri + $cmdbData.key # $fulluri = $uri + $cmdbData.key
$fulluri = "https://samaritanhealth-amc.ivanticloud.com/login.aspx?Scope=ObjectWorkspace&CommandId=Search&ObjectType=CI%23" + $cmdbdata.CIType + "&CommandData=RecId%2C%3D%2C0%2C" + $cmdbdata.RecId + "%2Cstring%2CAND%2C%7C"
Start-Process $fulluri Start-Process $fulluri
return return
} }

View file

@ -21,46 +21,69 @@ function Get-SHSPrinter {
foreach ($printer in $printers) { foreach ($printer in $printers) {
#Gets the printer ip and full domain name #Gets the printer ip and full domain name
$hit = $false $result = Get-PrinterIP $printer
$domains = @('.gsrmc.int.samhealth.net', '.avery.int.samhealth.net', '.sagh.int.samhealth.net', '.snlh.int.samhealth.net', '.slch.int.samhealth.net', '.spch.int.samhealth.net')
$result = Resolve-DnsName $printer -ErrorAction SilentlyContinue
if ($null -eq $result) {
$hit = $false
foreach ($domain in $domains) {
$search = "$printer$domain"
$result = Resolve-DnsName $search -ErrorAction SilentlyContinue
if ($null -ne $result) {
$hit = $true
$name = $result.Name
$ip = $result.IPAddress
}
}
if ($null -eq $result) {
if ($hit -eq $false) {
$ip = $null
$name = $null
}
}
}
else {
$name = $result.Name
$ip = $result.IPAddress
}
$result = [ordered]@{Hostname = $printer
IP = $ip
Path = $name
}
#CMDB Data #CMDB Data
if ($null -ne $result.IP) { # $cmdbRecord = Get-LANDeskCMDBItem -Name $printer
$cmdbRecord = Search-ISMBO -BO cis -filter "Name eq '$Printer'" -RawFilter
$LocationConstructors = @(
"SHS_AssetLocality",
"ivnt_Location",
"SHS_Floor",
"SHS_Department",
"SHS_LocationDetails"
)
$LocationData = Foreach($Loc in $LocationConstructors){
if ($Loc -eq 'SHS_Floor'){
$(if ($cmdbRecord.$Loc -match '-'){$cmdbRecord.$Loc.split('-')[-1] + " Floor"} else{$cmdbRecord.$Loc})
} elseif (![string]::IsNullOrEmpty($cmdbRecord.$Loc)){
$cmdbRecord.$Loc
}
}
$LocationData = $LocationData -join ' | '
# $locationData = $cmdbRecord.SHS_AssetLocality + " | " + $cmdbRecord.ivnt_Location + " | " + + " | " + $cmdbRecord.SHS_Department + " | " + $cmdbRecord.SHS_LocationDetails
# if($cmdbRecord.values._SHSLocation3.Length -gt $cmdbRecord.values._SHSCalcLocationString.Length){
# $locationData = $cmdbRecord.values._SHSLocation3
# }
# else{
# $locationData = $cmdbRecord.values._SHSCalcLocationString
# }
if($cmdbRecord){
# $CMDB_POA = $cmdbRecord.values._SHSPOANumber
# $CMDB_AssetTag = $cmdbRecord.values._SHSAssetTag
# $CMDB_Location = $locationData
# $CMDB_MAC = $cmdbRecord.values._SHSMACAddress
# $CMDB_model = $cmdbRecord.values._Model
# $CMDB_serial = $cmdbRecord.values._SerialNumber
# $CMDB_IP = $cmdbRecord.values._IPAddress
### Spark Properties
$CMDB_POA = $cmdbRecord.SHS_POANumber
$CMDB_AssetTag = $cmdbRecord.AssetTag
$CMDB_Location = $locationData
$CMDB_MAC = $cmdbRecord.MACAddress
$CMDB_model = $cmdbRecord.Model
$CMDB_serial = $cmdbRecord.SerialNumber
$CMDB_IP = $cmdbRecord.IPAddress
}
else{
$CMDB_POA = "*CMDB Mismatch - check CMDB*"
$CMDB_AssetTag = "*CMDB Mismatch - check CMDB*"
$CMDB_Location = "*CMDB Mismatch - check CMDB*"
$CMDB_MAC = "*CMDB Mismatch - check CMDB*"
$CMDB_model = "*CMDB Mismatch - check CMDB*"
$CMDB_serial = "*CMDB Mismatch - check CMDB*"
$CMDB_IP = "*CMDB Mismatch - check CMDB*"
}
if($result.IP -ne $null) {
$printerip = $result.IP $printerip = $result.IP
$domainName = $result.Path $domainName = $result.Path
@ -68,6 +91,8 @@ function Get-SHSPrinter {
#checks to see if the printer is online #checks to see if the printer is online
$online = Test-Connection $printerip -ErrorAction SilentlyContinue $online = Test-Connection $printerip -ErrorAction SilentlyContinue
if($online){ if($online){
#opens snmp connection to the printer #opens snmp connection to the printer
$snmp.open($printerip, 'public', 2, 3000) $snmp.open($printerip, 'public', 2, 3000)
@ -91,7 +116,7 @@ function Get-SHSPrinter {
try { if ($snmp.Get('.1.3.6.1.2.1.43.11.1.1.6.1.2') -match 'Toner|Cartridge|ink') { $color = 'Yes' } else { $color = 'No' } } catch { $color = 'No' } try { if ($snmp.Get('.1.3.6.1.2.1.43.11.1.1.6.1.2') -match 'Toner|Cartridge|ink') { $color = 'Yes' } else { $color = 'No' } } catch { $color = 'No' }
# TRAYS # TRAYS
try { $trays = $($snmp.GetTree('.1.3.6.1.2.1.43.8.2.1.13') | Where-Object { $_ -notlike 'print*' }) -join ';' } catch { $trays = $null } try { $trays = $($snmp.GetTree('.1.3.6.1.2.1.43.8.2.1.13') | ? {$_ -notlike 'print*'}) -join ';' } catch { $trays = $null }
# SERIAL # SERIAL
try { $serial = $snmp.Get('.1.3.6.1.2.1.43.5.1.1.17.1') } catch { $serial = $null } try { $serial = $snmp.Get('.1.3.6.1.2.1.43.5.1.1.17.1') } catch { $serial = $null }
@ -280,6 +305,9 @@ function Get-SHSPrinter {
#Addresses = $addr #Addresses = $addr
PageCount = $pagecount PageCount = $pagecount
Supplies = $supplies Supplies = $supplies
'CMDB POA' = $CMDB_POA
'CMDB AssetTag' = $CMDB_AssetTag
'CMDB Location' = $CMDB_Location
} }
$obj = New-Object -TypeName PSObject -Property $props $obj = New-Object -TypeName PSObject -Property $props
$snmp.close() $snmp.close()
@ -288,19 +316,27 @@ function Get-SHSPrinter {
} }
} }
if($CMDB_IP){
$offlineIP = 'CMDB IP - ' + $CMDB_IP
}
else{
$offlineIP = 'No DNS Entry'
}
$props = [Ordered]@{ $props = [Ordered]@{
Machine = $printer Machine = $printer
Status = 'No DNS Entry' Status = 'No DNS Entry'
IP = 'No DNS Entry' IP = $offlineIP
DomainName = 'No DNS Entry' DomainName = 'No DNS Entry'
MAC = 'No DNS Entry' MAC = $CMDB_MAC
Model = 'No DNS Entry' Model = $CMDB_model
Serial = 'No DNS Entry' Serial = $CMDB_serial
#Comment = $comment #Comment = $comment
Color = 'No DNS Entry' Color = 'No DNS Entry'
Trays = 'No DNS Entry' Trays = 'No DNS Entry'
PageCount = 'No DNS Entry' PageCount = 'No DNS Entry'
'CMDB POA' = $CMDB_POA
'CMDB AssetTag' = $CMDB_AssetTag
'CMDB Location' = $CMDB_Location
} }
$obj = New-Object -TypeName PSObject -Property $props $obj = New-Object -TypeName PSObject -Property $props
$snmp.close() $snmp.close()
@ -320,12 +356,12 @@ function Get-PrinterIP {
$domains = @('.gsrmc.int.samhealth.net','.avery.int.samhealth.net','.sagh.int.samhealth.net','.snlh.int.samhealth.net','.slch.int.samhealth.net','.spch.int.samhealth.net') $domains = @('.gsrmc.int.samhealth.net','.avery.int.samhealth.net','.sagh.int.samhealth.net','.snlh.int.samhealth.net','.slch.int.samhealth.net','.spch.int.samhealth.net')
$result = Resolve-DnsName $printer -ErrorAction SilentlyContinue $result = Resolve-DnsName $printer -ErrorAction SilentlyContinue
if ($null -eq $result) { if($result -eq $null){
$hit = $false $hit = $false
foreach ($domain in $domains) { foreach ($domain in $domains) {
$search = "$printer$domain" $search = "$printer$domain"
$result = Resolve-DnsName $search -ErrorAction SilentlyContinue $result = Resolve-DnsName $search -ErrorAction SilentlyContinue
if ($null -ne $result) { if($result -ne $null){
$hit = $true $hit = $true
$name = $result.Name $name = $result.Name
$ip = $result.IPAddress $ip = $result.IPAddress
@ -335,7 +371,7 @@ function Get-PrinterIP {
} }
if ($null -eq $result) { if($result -eq $null){
if($hit -eq $false){ if($hit -eq $false){
$ip = $null $ip = $null
$name = $null $name = $null
@ -367,10 +403,10 @@ function Start-SHSPrinterWeb {
process { process {
if($printer.DomainName -ne 'No DNS Entry' -and $printer.MAC -ne 'Offline'){ if($printer.DomainName -ne 'No DNS Entry' -and $printer.MAC -ne 'Offline'){
$domainName = $printer.DomainName $domainName = $printer.DomainName
Start-Process "http://$domainName" start "http://$domainName"
$mac = $printer.MAC $mac = $printer.MAC
Start-Sleep -Seconds 1 Sleep -Seconds 1
Start-Process "https://shsorion/Orion/UDT/EndpointDetails.aspx?NetObject=UE-MAC:VAL=$mac" start "https://shsorion/Orion/UDT/EndpointDetails.aspx?NetObject=UE-MAC:VAL=$mac"
} }
else{ else{

View file

@ -0,0 +1,393 @@
Function Search-ISMBusinessObject {
<#
.SYNOPSIS
Searches business objects for records matching the supplied criteria/filter.
.DESCRIPTION
This function will fetch a business object(s) for records that equal the supplied criteria in the -Filter parameter.
Only the following eight operators are supported when fetching business object records using the filter function:
eq - Returns true if the first value is equal to the second value.
ne - Returns true if the first value is not equal to the second value.
lt - Returns true if the first value is less than the second value.
le - Returns true if the first value is less than or equal to the second value.
gt - Returns true if the first value is greater than the second value.
ge - Returns true if the first value is greater than or equal to the second value.
or - Returns true if either one of its left or right sub-expressions evaluates to true.
and - Returns true if both its left and right sub-expressions evaluate to true.
.PARAMETER -BusinessObject
The Business Object you are interacting with. (Incidents, CIs, CI__ActiveDirectorys, ServiceReqs, Locations, Employees, Manufacturers, StandardUserTeams, Problems, Changes, etc...)
.PARAMETER -Filter
The filter containing your search string. This parameter allowed queries to be constructed using a more "friendly" syntax and additionally supports submitting the API call as entered explicitly.
The filter must be formatted properly to be parsed correctly by the API. Please see the examples in the help for more information.
.PARAMETER -RawFilter
An optional switch parameter that can be used to force the function to pass exactly the -filter string as supplied with no additional parsing. When this switch isn't used, the function will default to parsing the filter in an attempt to make it easier to format queries which includes requiring operators be preceded by hyphens. (-eq, -and, etc...)
.PARAMETER -Testing
Hidden optional parameter that is useful for outputting additional debugging information when troubleshooting the function.
.PARAMETER -DetailedOutput
Hidden optional parameter that will return the API URI submitted for outputting additional debugging information when troubleshooting the function.
.INPUTS
Parent and Child RecIDs, Action and Relationship.
.OUTPUTS
Returns the newly created Relationship Business Object on success.
.NOTES
Version: 1.0
Author: Sean Carlton
Creation Date: 08/16/2022
Purpose/Change: Initial script development
.EXAMPLE
Search-ISMBusinessObject -BusinessObject employees -Filter "primaryemail -eq johnsmith@email.com"
=======
This example demonstrates searching the employees business object where the primaryemail property is equal to johnsmith@email.com.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject cis -Filter "createdby -eq jsmith -and name -eq 3M - File Extract Process"
=======
This example demonstrates searching the cis business object where the createdby user is equal to jsmith AND the name of the record is equal to 3M - File Extract Process.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject incidents -Filter "incidentnumber -eq 11504"
=======
This example demonstrates searching the incidents business object where the incident number is equal to 11504.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject locations -Filter "name -eq SAGH Campus - ''88 Bldg"
=======
This example demonstrates using the apostrophe as an escape character. The Location Name of SAGH Campus - '88 Bldg contains an apostrophe which is parsed by the REST API and so it must be escaped with an apostrophe (') so the search query executes successfully.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject cis -Filter "name eq 'IL GEM 4000 2 SAGH'" -RawFilter
=======
This example demonstrates searching the cis business object where the name of the record is equal to IL GEM 4000 2 SAGH. The -RawFilter switch will submit the provided filter exactly as typed to the API. Notice that there is no hypen before the operator (eq) and the value is wrapped in single quotes.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject cis -Filter "CreatedDateTime -gt 2022-07-24T23:42:48Z"
=======
This example demonstrates searching the cis business object where the CreatedDateTime of the record is greater than 2022-07-24T23:42:48Z.
=======
.EXAMPLE
Search-ISMBusinessObject -BusinessObject cis -Filter "CreatedDateTime gt 2022-07-24T23:42:48Z" -RawFilter
=======
This example demonstrates searching the cis business object where the CreatedDateTime of the record is greater than 2022-07-24T23:42:48Z but using the -RawFilter switch parameter. Notice there is no hyphen before the operator (gt) and that in this particular instance, the value supplied is NOT wrapped in single quotes. Not all fetch calls to the API require the value be wrapped in single quotes depending on the type of field being queried for.
=======
.EXAMPLE
Search-ISMBusinessObject -businessobject frs_data_workflow_historys -filter "BlockException ne '`$NULL'" -RawFilter
=======
This example demonstrates searching a business object and evaluating a NULL property value. The null property must be in all caps and be preceded with $ for the REST API to parse it properly.
=======
#>
[CmdletBinding()]
param (
[Alias("BO")]
[Parameter(
HelpMessage = 'Business Object Type you are Querying Against (Incidents, ServiceReqs, cis, etc...)',
Mandatory = $true)]
[string]$BusinessObject,
[Parameter(
HelpMessage = 'Format: Property -eq ''Value'',
Ex: displayname -eq ''John Batman''',
Mandatory=$true)]
[string]$Filter,
[Parameter(Helpmessage = "
Ex: Search-ISMBusinessObject -BusinessObject cis -Filter ""createdby eq 'scarlton' and name eq 'IL GEM 4000 2 SAGH'"" -RawFilter
")]
[switch]$RawFilter, #// Switch to pass the filter value literally. This accounts for scenarios where the default -filter parsing fails/doesn't work. Primary differences include no hyphen prefix for Operators and wrapping the value in single quotes for most values (but not all! If your query is failing, try wrapping the value in single quotes and try again without.)
[Parameter(HelpMessage="Optional hidden parameter that will output additional information useful for debugging the function.",
Mandatory=$false,
DontShow)]
[switch]$Testing,
[Parameter(HelpMessage="Optional hidden parameter that can be used to ouput additional information.",
Mandatory=$false,
DontShow)]
[switch]$DetailedOutput,
### API Connection Parameters ###
[Parameter(HelpMessage = 'Tenant URL', DontShow)]
[string]$Tenant = (Connect-ISM)[1],
[Parameter(HelpMessage = 'Authorization Header', DontShow)]
[hashtable]$Headers = (Connect-ISM)[0]
)
BEGIN {
#Presume the syntax is valid to start
$ValidSyntax = $true
### Initialize an array for all errors/exceptions
$ExceptionErrors = @()
### Query for BusinessObject Metadata Properties
$BOMetaDataProperties = (Get-ISMBusinessObject -BusinessObject $BusinessObject -Metadata)
### If we have no BOMetaDataProperties then an invalid BusinessObject was supplied.
if (!$BOMetaDataProperties){
$ValidSyntax = $false
Write-Host "Unable to query Metadata for the $BusinessObject Business Object! Check the name and try again." -ForegroundColor yellow
} elseif ($BOMetaDataProperties.EntityType.count){
$BOMetaDataProperties = $BOMetaDataProperties.EntityType[-1].Property.Name | Sort-Object
} else {
$BOMetaDataProperties = $BOMetaDataProperties.EntityType.Property.Name
}
# Parse the filter accordingly based on whether the -RawFilter switch was provided or not.
if ($RawFilter -and $ValidSyntax){
$FilterEncodes = [ORDERED]@{
RAW_Filter = $Filter #\\Filter literally as entered by the user.
## Commented out on 01/16/23. Caused false-positive errors getting logged in $Error
## HTTP_Parsed_RAW = [System.Web.HTTPUtility]::UrlEncode(($Filter))#\\URL-Encoded with single quotes around the query.
## Commented out on 01/16/23
}
} elseif ($ValidSyntax) {
#Define the list of valid filter operators
$ValidOperators = @("-eq","-ne","-lt","-gt","-ge","-or","-and")
#Trim any whitespace from the beginning and end of the submitted filter query.
$Filter = $Filter.trim()
#Split out the provided filter on the spaces.
$FilterSplit = ($Filter -split '(?= )').trim()
#Parse the array. We can tell the Property Names and Operators apart from the values by querying for the metadata and comparing the operators to the supported operators.
$i = 0
$SplitArray = @()
Foreach ($Split in $FilterSplit){
$SplitObj = [PSCustomObject]@{
Split = $Split
Type = $null
NextSplit = $null
SplitQuoted = $null
SplitOpenQuote = $null
SplitCloseQuote = $null
Count = $i
ValidBOProperty = $false
}
if ($Split -in $ValidOperators){
$SplitObj.Split = $SplitObj.Split.Replace("-","")
$SplitObj.Type = "Operator"
$SplitObj.NextSplit = "Value"
} elseif ($SplitObj.Split -in $BOMetaDataProperties) {
$SplitObj.ValidBOProperty = $true
$SplitObj.Type = "Property"
$SplitObj.NextSplit = "Operator"
}else {
$SplitObj.Type = "Value"
$SplitObj.NextSplit = "Unknown"
}
$SplitObj.SplitQuoted = "'" + $SplitObj.Split + "'"
$SplitObj.SplitOpenQuote = "'" + $SplitObj.Split
$SplitObj.SplitCloseQuote = $SplitObj.Split + "'"
$SplitArray += $SplitObj
$i++
}
## Removed on 8/15/22 to ensure the fallback to the raw filter functionality works
# if ("Operator" -notin $SplitArray.Type){
# Write-host "Your filter query appears to have no valid operators. Operators must be formatted with a preceding hyphen and be in the list of valid operators: $($ValidOperators -join ", ")`n`nExample: ""LoginID -eq $($ENV:Username)""`nExample: ""CreatedDateTime -lt 2022-01-24T23:42:48Z""`n`nIf your filter query is correct as formatted, please use the -RawFilter switch to query the API with your literal query string." -ForegroundColor yellow
# $ValidSyntax = $false
# }
# Build the filter string based on the Type derived.
$FilterStringQuoted = @()
$FilterStringUnquoted = @()
$i = 0
foreach ($Split in $SplitArray){
#Add the raw value of the Split to the unquoted filter string.
$FilterStringUnquoted += $Split.Split
if ($Split.Type -eq "Value"){
If ($SplitArray[$i-1].Type -eq "Operator" -and $SplitArray[$i+1].Type -eq "Operator") {
$FilterStringQuoted += $Split.SplitQuoted
} elseif ($SplitArray[$i-1].Type -eq "Operator" -and (!$SplitArray[$i+1].Type)){
$FilterStringQuoted += $Split.SplitQuoted
} elseif ($SplitArray[$i-1].Type -eq "Operator"){
$FilterStringQuoted += $Split.SplitOpenQuote
} elseif ($SplitArray[$i+1].Type -eq "Operator") {
$FilterStringQuoted += $Split.SplitCloseQuote
} elseif ($SplitArray[$i+1].Type -eq "Property"){
$FilterStringQuoted += $Split.SplitCloseQuote
} elseif ($SplitArray[$i+1].Type -eq "Property") {
$FilterStringQuoted += $Split.SplitCloseQuote
} elseif ((!$SplitArray[$i+1].Type)){
$FilterStringQuoted += $Split.SplitCloseQuote
} else {
$FilterStringQuoted += $Split.Split
}
} else {
$FilterStringQuoted += $Split.Split
}
$i++
}
#Create an ordered hashtable with all of the parsed queries.
$FilterEncodes = [ORDERED]@{
HTTP_Parsed_With_Quotes = [System.Web.HTTPUtility]::UrlEncode(($FilterStringQuoted -join " "))#\\URL-Encoded with single quotes around the query.
HTTP_Parsed_No_Quotes = [System.Web.HTTPUtility]::UrlEncode(($FilterStringUnquoted -join " ")) #\\URL-Encoded without single quotes around the query.
RAW_With_Quotes = ($FilterStringQuoted -join " ") #\\Raw with single-quotes parsed around the query.
RAW_No_Quotes = ($FilterStringUnquoted -join " ") #\\Raw except perators have had the preceding - removed.
RAW_Filter = $Filter #\\Filter literally as entered by the user.
}
if ("Property" -notin $SplitArray.Type){
$ValidSyntax = $false
$PropertyHelper = Get-ISMBusinessObject -BusinessObject $BusinessObject -PropertyMatch $($FilterSplit[0])
$PropertyHelperMsg = $null
if ($PropertyHelper){
$PropertyHelperMsg = "`nPerhaps one of these matching fields is what you're looking for:`n$($PropertyHelper.Name -join "`n")`n"
}
Write-Host "The ""$($FilterSplit[0])"" property provided does not appear to be a valid property name on the $BusinessObject BusinessObject!`n$PropertyHelperMsg`nTo see a list of ALL valid properties run the following command:`n`nGet-ISMBusinessObject -BusinessObject $BusinessObject -PropertyList" -ForegroundColor yellow
# if ($DetailedOutput){
# # Write-Host "The ""$($FilterSplit[0])"" property provided does not appear to be a valid property name on the $BusinessObject BusinessObject!`n`n$BusinessObject has the following properties available:
# # $($BOMetaDataProperties -join ", ")" -ForegroundColor yellow
# } else {
# Write-Host "The ""$($FilterSplit[0])"" property provided does not appear to be a valid property name on the $BusinessObject BusinessObject!`n`nTo see a list of valid properties run the following command:`n`nGet-ISMBusinessObject -BusinessObject $BusinessObject -PropertyList" -ForegroundColor yellow
# }
}
}#End Else-if No -RawFilter Switch
}#END BEGIN
PROCESS {
if ($ValidSyntax){
#Initialize the results array.
$Results = @()
#Iterate through every encoded filter until we get results. This is to account for the various ways in which the API will fail to parse the filter query.
Foreach ($FilterEncode in $FilterEncodes.Keys){
if ($Testing){
Write-Host "Testing with $FilterEncode!" -foregroundcolor yellow
}
$uri = "$Tenant/api/odata/businessobject/$BusinessObject`?`$filter=$($FilterEncodes[$FilterEncode])&`$top=100&`$skip=0"
try{
$Query = $null
$Query = Invoke-RestMethod -Method GET -uri $uri -headers $headers
}
catch {
$ExceptionErrors += $_.Exception.Message
}
If ($Query.'@odata.count'){
if ($Testing){
Write-Host "Success using $FilterEncode!`n`nFilter Passed: $($FilterEncodes[$FilterEncode])`n`nWorking URI: $URI
" -foregroundcolor green
}
$Results += $Query.Value
if ($Results.Count -lt $Query.'@odata.count'){
Do {
$Skip = $Results.Count
$uri = "$Tenant/api/odata/businessobject/$BusinessObject`?`$filter=$($FilterEncodes[$FilterEncode])&`$top=100&`$skip=$Skip"
$SkipQuery = Invoke-RestMethod -Method GET -uri $uri -headers $headers
if ($SkipQuery){
$Results += $SkipQuery.Value
} else {
if ($Skip -lt $Query.'@odata.count'){
#If there's no SkipQuery but we have more results than the original queried @odata.count we won't bother with a warning. This can occur when looping through records when a new record is created during the loop.
Write-Warning "Failed query for $BusinessObject! (Skip: $Skip | Total: $($Query.'@odata.count'))"
}
$ExitLoop = $true
}
} until (($Results.Count -ge $Query.'@odata.count') -or $ExitLoop)
}
#Friendly little helper loop to parse employee business object MemberOf HTML fields into a proper array.
if ($BusinessObject -eq "employees"){
Foreach ($Employee in $Results){
$Employee | Add-Member -MemberType NoteProperty -Value @() -Name "SHS_MemberOfParsed" -force
if ($Employee.SHS_MemberOf){
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOf.replace("<br>","%").split("%").trim()
$Employee.SHS_MemberOfParsed = $Employee.SHS_MemberOfParsed | Sort-Object
}
}
}
break
} else {
if ($DetailedOutput){
Write-Host "Query Error: $($ExceptionErrors[-1])" -ForegroundColor red
}
}
}#END FOREACH
}#END IF VALID-SYNTAX
}#END PROCESS
END {
if ($DetailedOutput -and !$Results){
Write-host "No results found querying $BusinessObject with the provided filter!" -ForegroundColor yellow
} elseif ($DetailedOutput -and $Results){
Write-Host "Successful query!`n`nAPI URI: $uri`n`n" -foregroundcolor green
return $Results
} else {
return $Results
}
}#END END-BLOCK
}#END Search-ISMBusinessObject Function
New-Alias -Name Search-ISMBO -Value Search-ISMBusinessObject -Force

View file

@ -0,0 +1,383 @@
function Set-CMDBLocation {
[CmdletBinding()]
param (
[Parameter()]
[string]
$Hostname
)
process {
try {
## $cmdbData = Get-LANDeskCMDBItem -Name $Hostname
$cmdbRecord = Search-ISMBO -BO cis -filter "Name eq '$Hostname'" -RawFilter
} catch { $cmdbData = $null}
if($null -eq $cmdbData){
$getpcData = Get-PCBatchInvoke $Hostname
$asset = $getpcData.'Asset Tag'
$asset = $asset -split ' '
$asset = $asset[0]
try {
## $cmdbData = Get-LANDeskCMDBItem -AssetTag $asset
$cmdbData = Search-ISMBO -BO cis -filter "AssetTag eq '$asset'" -RawFilter
} catch{ $cmdbData = $null }
if($null -eq $cmdbData){
Write-Warning "Unable to find record with that hostname or assset tag in CMDB"
return
}
}
$oldLocation = $cmdbData.Values._SHSLocation3
$key = $cmdbData.key
Write-Host "Hostname: $hostname"
Write-Host "Current Location: $oldLocation"
$newLocation = Read-Host "New Location"
try {Set-LANDeskCMDBWorkstation -LocationDetails $newLocation -Key $key | Out-Null }
catch {
Write-Warning "Unable to change location data"
return
}
try {
## $cmdbData = Get-LANDeskCMDBItem -Name $Hostname
$cmdbData = Search-ISMBO -BO cis -filter "Hostname eq '$Hostname'" -RawFilter
} catch { $cmdbData = $null}
if($null -eq $cmdbData){
try {
##$cmdbData = Get-LANDeskCMDBItem -AssetTag $asset
$cmdbData = Search-ISMBO -BO cis -filter "AssetTag eq '$asset'" -RawFilter
} catch{ $cmdbData = $null }
if($null -eq $cmdbData){
Write-Warning "Unable to find record with that hostname or assset tag in CMDB"
return
}
}
$newLocation = $cmdbData.values._SHSLocation3
Write-Host "Location now set to: $newLocation" -ForegroundColor Green
}
}
function Set-LANDeskCMDBLocation {
[CmdletBinding(DefaultParameterSetName="Default")]
param (
[Parameter(HelpMessage = 'The Name of the new CMDB item',
Mandatory = $true
)]
[string]$Name,
[Parameter(HelpMessage = 'Enter the Location Details for the CMDB Item')]
[string]$LocationDetails,
[Parameter(HelpMessage = 'Enter the GUID for the CMDB Item')]
[string]$Key,
[Parameter(HelpMessage = 'Specifying Server',
Mandatory = $false,
DontShow = $true)]
[string] $server = $(Connect-LANDesk)[1],
[Parameter(HelpMessage = 'Specifying LanDesk Framework for api',
Mandatory = $false,
DontShow = $true)]
[string] $framework = $(Connect-LANDesk)[2],
[Parameter(HelpMessage = 'Specifying LanDesk Headers for api',
Mandatory = $false,
DontShow = $true)]
[hashtable] $Headers = $(Connect-LANDesk)[0]
)
begin {
}
process {
[object[]]$Values = $null
$Title = @{}
$Title.Name = "Title"
$Title.Value = $Name
[object[]]$Values += $Title
<#
$_ConfigTypesCategory = @{}
$_ConfigTypesCategory.Name = "_ConfigTypesCategory"
$_ConfigTypesCategory.Value = '9dadd9f9-ca5d-4be6-93cc-6c8745fff615'
$Values += $_ConfigTypesCategory
#>
$LocationDetails
$_SHSLocation3 = @{}
$_SHSLocation3.Name = "_SHSLocation3"
$_SHSLocation3.Value = $LocationDetails
$Values += $_SHSLocation3
$body = [ordered]@{}
$body.class_name = '_CMDBManagement.Call'
$Body.originalValues = $Values
$body.formValues = $Values
$body = $body | ConvertTo-Json
$uri = 'http://' + $server + '/' + $framework + '/api/form?class_name=_CMDBManagement.Call&key=' + $Key + '&function_name=Edit&v=*'
Invoke-RestMethod -Uri $uri -Headers $headers -Body $Body -Method Patch
}
end {
}
}
function Set-LANDeskCMDBWorkstation {
[CmdletBinding(DefaultParameterSetName="Default")]
param (
[Parameter(HelpMessage = 'The Name of the new CMDB item')]
[string]$Name,
[Parameter(HelpMessage = 'Enter the PO for the CMDB Item')]
[string]$PO,
[Parameter(HelpMessage = 'Enter the Physical Location for the CMDB Item')]
[string]$PhysicalLocation,
[Parameter(HelpMessage = 'Enter the Asset Tag for the CMDB Item')]
[string]$AssetTag,
[Parameter(HelpMessage = 'Enter the RequestID for the CMDB Item')]
[string]$RequestID,
[Parameter(HelpMessage = 'Enter the OperatingSystem for the CMDB Item')]
[string]$OperatingSystem,
[Parameter(HelpMessage = 'Enter the ChassisType for the CMDB Item')]
[string]$ChassisType,
[Parameter(HelpMessage = 'Enter the Total Hard Drive Size for the CMDB Item')]
[string]$HDD,
[Parameter(HelpMessage = 'Enter the RAM for the CMDB Item')]
[string]$RAM,
[Parameter(HelpMessage = 'Enter the Hard drive space Avalible for the CMDB Item')]
[string]$HDDAvail,
[Parameter(HelpMessage = 'Enter the IPAddress for the CMDB Item')]
[string]$IPAddress,
[Parameter(HelpMessage = 'Enter the KioskRole for the CMDB Item')]
[string]$KioskRole,
[Parameter(HelpMessage = 'Enter the Model for the CMDB Item')]
[string]$Model,
[Parameter(HelpMessage = 'Enter the SerialNumber for the CMDB Item')]
[string]$SerialNumber,
[Parameter(HelpMessage = 'Enter the Notes for the CMDB Item')]
[string]$Notes,
[Parameter(HelpMessage = 'Enter the OSPatching for the CMDB Item')]
[string]$OSPatching,
[Parameter(HelpMessage = 'Enter the Patch Schedule for the CMDB Item')]
[string]$PatchSchedule,
[Parameter(HelpMessage = 'Enter the Patch Notes for the CMDB Item')]
[string]$PatchNotes,
[Parameter(HelpMessage = 'Enter the Location Details for the CMDB Item')]
[string]$LocationDetails,
[Parameter(HelpMessage = 'Enter the GUID for the CMDB Item',
Mandatory = $true)]
[string]$Key,
[Parameter(HelpMessage = 'Specifying Server',
Mandatory = $false,
DontShow = $true)]
[string] $server = $(Connect-LANDesk)[1],
[Parameter(HelpMessage = 'Specifying LanDesk Framework for api',
Mandatory = $false,
DontShow = $true)]
[string] $framework = $(Connect-LANDesk)[2],
[Parameter(HelpMessage = 'Specifying LanDesk Headers for api',
Mandatory = $false,
DontShow = $true)]
[hashtable] $Headers = $(Connect-LANDesk)[0]
)
begin {
}
process {
[object[]]$Values = $null
if($Name){
$Title = @{}
$Title.Name = "Title"
$Title.Value = $Name
[object[]]$Values += $Title
}
<# $_ConfigTypesCategory = @{}
$_ConfigTypesCategory.Name = "_ConfigTypesCategory"
$_ConfigTypesCategory.Value = '9dadd9f9-ca5d-4be6-93cc-6c8745fff615'
$Values += $_ConfigTypesCategory #>
if ($PO) {
$_PO = @{}
$_PO.Name = "_PO"
$_PO.Value = $PO
$Values += $_PO
}
# Look up table
if ($PhysicalLocation) {
$Location = Search-LANDeskIssueLocation -Location $PhysicalLocation
$_CILocation = @{}
$_CILocation.Name = "_CILocation"
$_CILocation.Value = $Location.Key
$Values += $_CILocation
}
if ($AssetTag) {
$_SHSAssetTag = @{}
$_SHSAssetTag.Name = "_SHSAssetTag"
$_SHSAssetTag.Value = $AssetTag
$Values += $_SHSAssetTag
}
if ($RequestID) {
$_RequestID = @{}
$_RequestID.Name = "_RequestID"
$_RequestID.Value = $RequestID
$Values += $_RequestID
}
# Look up table
if ($OperatingSystem) {
if($OperatingSystem -match 'Windows 10'){
$OS = '2ad72fd5-8d4e-4510-b5ea-f94b3a2cda08'
}
elseif ($OperatingSystem -match 'Windows 7') {
$OS = 'f127ceee-074b-4cc1-8a71-f8c02a9a9bd1'
}
else {
$OS = '00000000-0000-0000-0000-000000000000'
}
$_SHSOperatingSystem = @{}
$_SHSOperatingSystem.Name = "_SHSOperatingSystem"
$_SHSOperatingSystem.Value = $OS
$Values += $_SHSOperatingSystem
}
if ($ChassisType) {
if($ChassisType -match "Desktop" -or $ChassisType -match "SFF"){
$ChassisGuid = 'c7f3c5ba-a8b3-40be-963f-7e1d75fb7fda'
}
elseif ($ChassisType -match "Micro") {
$ChassisGuid = '8d71a4c3-ae9d-4e55-98ea-2f8a75987cac'
}
elseif($ChassisType -match "Laptop"){
$ChassisGuid = 'a8460b18-bab9-4c07-8fb1-a4cca4e63fa1'
}
elseif($ChassisType -match "Tablet"){
$ChassisGuid = 'e6ae9cd4-9936-496d-8e5d-efce8417a3d0'
}
else{
$ChassisGuid = '00000000-0000-0000-0000-000000000000'
}
$_SHSChassisType = @{}
$_SHSChassisType.Name = "_SHSChasisRef"
$_SHSChassisType.Value = $ChassisGuid
$Values += $_SHSChassisType
}
if ($HDD) {
$_HardDiskSize = @{}
$_HardDiskSize.Name = "_HardDiskSize"
$_HardDiskSize.Value = $HDD
$Values += $_HardDiskSize
}
if ($RAM) {
$_RAM = @{}
$_RAM.Name = "_RAM"
$_RAM.Value = $RAM
$Values += $_RAM
}
if ($HDDAvail) {
$_AvailableDiskSpace = @{}
$_AvailableDiskSpace.Name = "_AvailableDiskSpace"
$_AvailableDiskSpace.Value = $HDDAvail
$Values += $_AvailableDiskSpace
}
if ($IPAddress) {
$_IPAddress = @{}
$_IPAddress.Name = "_IPAddress"
$_IPAddress.Value = $IPAddress
$Values += $_IPAddress
}
if ($Model) {
$_Model = @{}
$_Model.Name = "_Model"
$_Model.Value = $Model
$Values += $_Model
}
if ($SerialNumber) {
$_SerialNumber = @{}
$_SerialNumber.Name = "_SerialNumber"
$_SerialNumber.Value = $SerialNumber
$Values += $_SerialNumber
}
if ($Notes) {
$_SHSCINotes = @{}
$_SHSCINotes.Name = "_SHSCINotes"
$_SHSCINotes.Value = $Notes
$Values += $_SHSCINotes
}
# Look up table
if ($OSPatching) {
$Patch = Search-LANDeskOSPatchType -PatchType $OSPatching
$_SHSOSPatching = @{}
$_SHSOSPatching.Name = "_SHSOSPatching"
$_SHSOSPatching.Value = $Patch.Key
$Values += $_SHSOSPatching
}
#look up table
if ($PatchSchedule) {
$Schedule = Get-LANDeskPatchSchedule -PatchSchedule $PatchSchedule
$_SHSPatchSchedule = @{}
$_SHSPatchSchedule.Name = "_SHSPatchSchedule"
$_SHSPatchSchedule.Value = $Schedule
$Values += $_SHSPatchSchedule
}
if ($PatchNotes) {
$_SHSPatchNotes = @{}
$_SHSPatchNotes.Name = "_SHSPatchNotes"
$_SHSPatchNotes.Value = $PatchNotes
$Values += $_SHSPatchNotes
}
if ($LocationDetails){
$LocationDetails
$_SHSLocation3 = @{}
$_SHSLocation3.Name = "_SHSLocation3"
$_SHSLocation3.Value = $LocationDetails
$Values += $_SHSLocation3
}
$body = [ordered]@{}
$body.class_name = '_CMDBManagement.Call'
$Body.originalValues = $Values
$body.formValues = $Values
$body = $body | ConvertTo-Json
$uri = 'http://' + $server + '/' + $framework + '/api/form?class_name=_CMDBManagement.Call&key=' + $Key + '&function_name=Edit&v=*'
Invoke-RestMethod -Uri $uri -Headers $headers -Body $Body -Method Patch
}
end {
}
}

View file

@ -1,57 +0,0 @@
$SparkHeaders = @{
"Content-Type" = "application/json"
"Authorization" = ""
"Accept" = "*/*"
"Accept-Encoding" = "gzip, deflate, br"
}
$SparkTenantPrefix = "samaritanhealth-amc"
$SparkURL = "https://$SparkTenantPrefix.ivanticloud.com"
Function Connect-ISM {
try {
#Try a fast route to check if authorization headers are set properly
Invoke-RestMethod -Method Get -URI "$SparkURL/api/odata" -Headers $SparkHeaders
} catch {
$errobject = ConvertFrom-Json $_
#A 404 means we were authorized and didn't find anything, as intended!
if ($errobject.code -eq "ISM_4004") { return }
#Anything other than a 401 Unauthorized is unexpected, attempt to handle gracefully
if ($errobject.code -ne "ISM_4001") {
Write-Host -ForegroundColor Red "Unexpected error connecting to Spark!"
Write-Host -ForegroundColor Red "$errobject"
$SparkHeaders["Authorization"] = ""
return
}
#Unuathorized response, so let's update our authorization!
if ( $SparkHeaders["Authorization"] ) {
Write-Host "Spark Authorization key expired, please update key"
}
$authKey = Read-Host "Login to Spark, open browser dev tools, and paste SID cookie here, or an API key if you have one"
if ($authKey -match "[0-9A-F](32)") {
$SparkHeaders["Authorization"] = "rest_api_key=$authKey"
} elseif ($authKey -match "$($SparkURL.split('/')[-1])#.*#") {
$SparkHeaders["Authorization"] = $authKey
} else {
Write-Host -ForegroundColor Yellow "Authorization key not a recognized key format"
$SparkHeaders["Authorization"] = ""
}
}
}
if ($(Read-Host "Enable Spark features? (y/N)") -match "^y") { Connect-ISM }
Function Get-SparkEnabled {
return -not -not $SparkHeaders["Authorization"]
}
Function Get-SparkCI($CIName) {
Connect-ISM
$uri = "$SparkURL/api/odata/businessobject/CIs`?`$filter=Name+eq+%27$CIName%27"
try{
$Query = Invoke-RestMethod -Method GET -uri $uri -headers $SparkHeaders
} catch {
$ExceptionErrors += $_.Exception.Message
}
return $Query.Value
}

View file

@ -0,0 +1,167 @@
Function Update-ISMBusinessObject {
<#
.SYNOPSIS
Updates business object field values for specific records.
.DESCRIPTION
By providing the Business Object and the Record ID (RecID), the function will dynamically query the Business Object's metadata to provide a parameter list of all available fields for that particular business object.
Additionally, use of the -RawJSONBody parameter allows a raw JSON payload to be passed directly if desired.
.PARAMETER -BusinessObject
The Business Object you are interacting with. (Incidents, CIs, CI__ActiveDirectorys, ServiceReqs, Locations, Employees, Manufacturers, StandardUserTeams, Problems, Changes, etc...)
.PARAMETER -RecID
The Record ID (RecID) of the specific record you wish to interact with.
.PARAMETER -RawJSONBody
Optional parameter for passing a raw JSON payload as opposed to letting the function dynamically query for the fields of the supplied business object and formatting the payload for you.
.PARAMETER -DetailedOutput
Optional parameter that will return the API URI and JSON Payload in addition to the standard output.
.INPUTS
Business Object, RecID and dynamic parameter values or a JSON payload.
.OUTPUTS
Returns the updated business object.
.NOTES
Version: 1.0
Author: Sean Carlton
Creation Date: 08/16/2022
Purpose/Change: Initial script development
.EXAMPLE
Update-ISMBusinessObject -BusinessObject cis -RecID "5788C7AB6E1E44AD8464FED18A510609" -Description "Important Description" -SHS_BusinessCriticality "Entity Essential"
=======
This example demonstrates updating the Description and SHS_BusinessCriticality fields on a CI record.
=======
.EXAMPLE
$JSON_Payload = @"
{
"Description": "Test Description",
"SHS_BusinessCriticality": "Normal"
}
"@
Update-ISMBusinessObject -BusinessObject cis -RecID "5788C7AB6E1E44AD8464FED18A510609" -RawJSONBody $JSON_Payload
=======
This example demonstrates updating the Description and SHS_BusinessCriticality fields on a CI record by passing a raw JSON payload using the -RawJSONBody parameter.
=======
.EXAMPLE
Update-ISMBusinessObject -BusinessObject employees -RecID "F922E4482A224E4FAE882D2B32AEBB6B" -DisplayName "John Smith"
=======
This example demonstrates updating the Display Name field on an employee record.
=======
#>
[CmdletBinding()]
param (
[Alias("BO")]
[Parameter(HelpMessage="The business object you intend to update",
Mandatory=$true)]
[string]
$BusinessObject,
[Parameter(HelpMessage="The Record ID of the record you want to update",
Mandatory=$true)]
[string]
$RecID,
[Parameter(HelpMessage="Optional parameter to pass a raw JSON Payload as opposed to leveraging the dynamic parameter query and generating the payload",
Mandatory=$false)]
[string]
$RawJSONBody,
[Parameter(HelpMessage="Optional parameter ouput the JSON Payload that was generated/sent along with the standard output of the function",
Mandatory=$false,
DontShow)]
[switch]
$DetailedOutput,
### API Connection Parameters ###
[Parameter(HelpMessage = 'Tenant URL', DontShow)]
[string]$Tenant = (Connect-ISM)[1],
[Parameter(HelpMessage = 'Authorization Header', DontShow)]
[hashtable]$Headers = (Connect-ISM)[0]
)
dynamicparam
{
#Create a parameter dictionary. This object is ultimately leveraged to create a parameter for every field returned from the metadata.
$paramDictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary
$BO_Attributes = (Get-ISMBusinessObject -BusinessObject $BusinessObject -Metadata)
if ($BO_Attributes.EntityType.count){
$BO_Attributes = $BO_Attributes.EntityType[-1].Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
} else {
$BO_Attributes = $BO_Attributes.EntityType.Property | Where-Object {$_.Name -ne "RecID"} | Sort-Object "Name"
}
Foreach ($Field in $BO_Attributes){
# write-host "Parsing $($Field.name) with type $($Field.Type)"
$Attribute = New-Object System.Management.Automation.ParameterAttribute
##Account for any datatype name discrepancies between Powershell and ISM
switch ($Field.Type.split(".")[1]){
"Date" {$AttributeType = "DateTime"}
"Boolean" {$AttributeType = "bool"}
"Byte" {$AttributeType = "Byte"}
"String" {$AttributeType = "String"}
default {$AttributeType = "String"}
}
$dynParam = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter($Field.Name,
$AttributeType, $Attribute)
$paramDictionary.Add($Field.Name, $dynParam)
}#End Foreach
#Return the collection of dynamic parameters
$paramDictionary
}#END DYNAMIC PARAMETER
BEGIN {
$URI = "$Tenant/api/odata/businessobject/$BusinessObject('$RecID')"
If ($RawJSONBody){
$Params = $RawJSONBody
} else {
$Params = $PSBoundParameters
$Params.Remove("BusinessObject") | Out-Null #//The Business Object is passed in the URI.
$Params.Remove("RecID") | Out-Null #//The RecID is passed in the URI.
$Params.Remove("DetailedOutput") | Out-Null #//Function-specific parameter.
$Params.Remove("RawJSONBody") | Out-Null #//Function-specific parameter.
$Params = $Params | ConvertTo-JSON
}
try {
$UpdatedBusObj = Invoke-RestMethod -Method PATCH -URI $uri -Headers $headers -Body $Params
}
catch {
write-warning "Failed updating the $BusinessObject Object with RecID $RecID!"
$_.ErrorDetails.Message
$_.Exception.Message
}
}
END{
if ($DetailedOutput){
return $UpdatedBusObj, $Params, $uri
} else {
return $UpdatedBusObj
}
}
}#END Update-ISMBusinessObject Function
New-Alias -Name Update-ISMBO -Value Update-ISMBusinessObject -Force

View file

@ -4,7 +4,7 @@
#region Module Import Block #region Module Import Block
$ErrorActionPreference = 'SilentlyContinue' #$ErrorActionPreference = 'SilentlyContinue'
#DevStage can take either Dev or Prod as values #DevStage can take either Dev or Prod as values
$devStage = 'Dev' $devStage = 'Dev'
#Locations for dev build and prod build #Locations for dev build and prod build
@ -125,6 +125,18 @@ Function Get-PC {
[Switch]$WinProfileRebuild [Switch]$WinProfileRebuild
) )
## Define which Spark Record Properties are Returned
$Spark_Property_Return = @(
"Name",
"ivnt_assetfulltype",
"ivnt_location",
"SHS_LocationDetails",
"AssetTag",
"SerialNumber",
"Owner",
"Status"
)
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Write-Warning "Get-PC requires powershell to be run as administrator. Please re-launch powershell as administrator." Write-Warning "Get-PC requires powershell to be run as administrator. Please re-launch powershell as administrator."
break break
@ -137,8 +149,6 @@ Function Get-PC {
return return
} }
if ($EnableSpark) { Connect-ISM }
if ($PatchNotes) { if ($PatchNotes) {
$scriptparent = (get-item $PSScriptRoot ).parent.FullName $scriptparent = (get-item $PSScriptRoot ).parent.FullName
Write-Host "`n" Write-Host "`n"
@ -153,6 +163,53 @@ Function Get-PC {
return return
} }
if($locationSearch){
Write-Host 'Please enter a partial location like a room number.'
$searchInput = Read-Host 'Location'
Write-Host "Searching CMDB for $searchInput ..."
<# $ComputerName
if($ComputerName.count -gt 1){
Write-Host 'Can only search a single location at a time' -ForegroundColor Yellow
return
} #>
if($searchInput.ToCharArray().Length -lt 3){
Write-Host 'Location searches much contain more than 2 characters' -ForegroundColor Yellow
return
}
$searchResults = Search-CMDB -Location $searchInput | Sort-Object -Property Hostname
if($searchResults -eq $null){
Write-Host 'No results for given search' -ForegroundColor Yellow
return
}
Write-Output $searchResults
return
}
$charA = $ComputerName.ToCharArray()
if($charA -contains '*'){
if($charA -lt 4){
Write-Host "Wildcard searches need to be at least 4 characters long" -ForegroundColor Red
return
}
Write-Host "Starting CMDB Wildcard Search..."
# $searchResults = Search-CMDB -hostname $ComputerName.Replace('*','') | Sort-Object -Property Hostname
$searchResults = Find-ISMBO -BusinessObject "cis" -SearchQuery $ComputerName.Replace('*','') | Sort-Object -Property Name
Write-Output $searchResults | Select-Object $Spark_Property_Return
if($TableView){
$searchResults | Select-Object $Spark_Property_Return | Out-GridView -Title 'Get-PC Wildcard Search'
}
return
}
$getPCComputers = @() #List of computers that will get a batch query $getPCComputers = @() #List of computers that will get a batch query
$outPutArray = @() #For use near the end of the script to output to users screen in a specified format $outPutArray = @() #For use near the end of the script to output to users screen in a specified format
$PCID = 1 #This is a helper variable for the progress bar $PCID = 1 #This is a helper variable for the progress bar