## Info ## ## __| __ __| | / __| ## ( | . < ( _ \ _| -_) ## \___| _| _|\_\ \___| \___/ _| \___| ## ## Author: Nielsen Pierce ## Updated by Martin Howlett and Mark Wichall ## Description: PSv3 module for Querying Core Device(s) from cmd line ## Requires Powershell v3 ## Version 2.4 - Added new version of get-coredevice(s) ## Version 2.3 - Improved Get-CoreToken and validation options around the token ## Version 2.2 - Removed backup IP after CORE update ## Version 2.1 - Removed backup IP after CORE update ## Version 2.0 ## Define Functions ## Global Authentication Cmdlets Function Get-CoreToken { Param( [Parameter()]$RSAToken ) $count = 0 While (-NOT $Response) { #The -erroraction param doesnt work on Invoke-RestMethod so we have to temporarily turn it off for the whole script $OldEAP = $ErrorActionPreference $ErrorActionPreference = 'SilentlyContinue' IF ([Environment]::GetEnvironmentVariable("CoreUser")) { $Username = [Environment]::GetEnvironmentVariable("CoreUser") } ELSE { #Prompt for user name $Username = Read-Host "Please enter your username to login to CORE" } if(-NOT $RSAToken){ $RSAToken = $([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($(Read-Host -Prompt "Please enter your RSA token to login to CORE" -AsSecureString)))) } #Send request to CORE and ask for the password $Response = Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/login/$username" -Body "{`"password`":`"$RSAToken`"}" -Method "Post" #Enable the error action again $ErrorActionPreference = $OldEAP #If we have not had a response from the invoke-restmethod then creds are probably wrong, so inform the user IF (-NOT $Response) { $count ++ If ($count -eq 3) { #After 3 tries break, else we will be here all day $CoreFailed = $true break } write-host "CORE Username or password incorrect, please retype credentials" -ForegroundColor Red $RSAToken = $null } } if(-not $CoreFailed){ #Save our username [Environment]::SetEnvironmentVariable("CoreUser",$Username, "User") #Save our token to our variables Save-COREToken -COREToken $Response.authtoken Return $Response.authtoken }else{ write-host "CORE credentials failed 3 times. Giving up!" -ForegroundColor Red break } } Function Save-COREToken { Param( [Parameter(Mandatory=$true)]$COREToken ) #Save the token and username to our Environment Variables [Environment]::SetEnvironmentVariable("CoreToken",$COREToken, "User") $Global:Token = $COREToken } Function Validate-CoreTokenRequest { Param( [Parameter(Mandatory=$true)]$COREToken ) #The -erroraction param doesnt work on Invoke-RestMethod so we have to temporarily turn it off for the whole script $OldEAP = $ErrorActionPreference $ErrorActionPreference = 'SilentlyContinue' $URL = "https://ws.core.rackspace.com/ctkapi/session/$COREToken" #I have seen a weird error where this command will return "The underlying connection was closed: An unexpected error occurred on a send." #As such if it comes back as blank we will try and webclient, which seems to work more reliably $tokenValid = Invoke-RestMethod -Uri $URL -Method GET IF (-NOT $tokenValid) { #try downloading via the web client $wc = New-Object System.Net.WebClient $tokenValid = ($wc.DownloadString($url)) | ConvertFrom-Json } #Enable the error action again $ErrorActionPreference = $OldEAP Return $tokenValid } Function Validate-CoreToken{ Param( [Parameter()][switch]$ReturnBooleen ) #Test the $Global:Token Variable $COREToken = $null $COREToken = $Global:token Write-Verbose "Global:Token: $COREToken" if ($Global:token -eq $null){ $Valid = $false Write-Verbose "Global:Token is null" }else{ $Valid = (Validate-CoreTokenRequest -COREToken $COREToken).valid Write-Verbose "Global:Token is $Valid after testing in CORE" } if($Valid){ Save-COREToken -COREToken $COREToken Write-Verbose "Saving existing Global:Token" if($ReturnBooleen){ return $true $NoMoreoutput = $true } }else{ #Test the Environment Variable $COREToken = $null $CoreToken = [Environment]::GetEnvironmentVariable("CoreToken") Write-Verbose "ENviroment token = $CoreToken" if ($CoreToken -eq $null){ $Valid = $false Write-Verbose "Enviroment token is null" }else{ $Valid = (Validate-CoreTokenRequest -COREToken $COREToken).valid Write-Verbose "Enviroment token is $Valid after testing in CORE" } } if(-NOT $NoMoreoutput){ if($Valid){ Save-COREToken -COREToken $COREToken Write-Verbose "Saving existing enviroment token" if($ReturnBooleen){ return $true } }else{ if($ReturnBooleen){ return $false }else{ $COREToken = Get-CoreToken Write-Verbose "Getting new token $COREToken" } } } } ## Define Core Module Functions Function Get-CoreQuery{ Param( [Parameter(Mandatory=$true)]$JSON ) #Search each line of the JSON, if load_arg is blank or NULL then cancel ForEach ($line in $JSON) { IF (($line -like "*load_arg*`"`"*") -OR ($line -like "*load_arg*`"NULL`"*")) { write-host "Blank or null value detected in line $line in CTKCore module. Cancelling script" -ForegroundColor Red exit } } #Make sure our token is valid Validate-CoreToken #Submit the CORE query Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/query" -Method "Post" -Headers @{"X-Auth"=$global:token} -Body $JSON -TimeoutSec 180 } ## Core CTKAPI Cmdlets # Get Functions Function Get-ComputerAttributes { Param( [Parameter ()][switch]$RackPW ) #Create array of all params we want to get from devices in CORE $ComputerAttributes = @( "account.name", "number", "name", "primary_ip", "primary_nat_ip", "is_windows", "os_name", "nickname", "status.active", "status.name", "os_type", "platform_name", "platform_type", "is_online", "datacenter.name", "datacenter.symbol", "ports.display_name", "vcc", "dracnet_ip", "account", "attached_devices", "is_windows", "offline_date", "attached_firewalls", "date_online", "account_domain_info.domain_name", "account_domain_info.add_userid_to_domain", "is_cluster", "aggexnet_vlans" ) #adds password info if required If ($RackPW) { $ComputerAttributes += "root_password" $ComputerAttributes += "rack_password" } Return $ComputerAttributes } Function Get-COREDevicePSobject { Param( [Parameter ()][switch]$RackPW, [Parameter()]$Computers, [Parameter()][switch]$NoDRAC, [Parameter()][switch]$GetIP, #get ips from IP commander (adds 3 seconds) [Parameter ()]$IPs ) IF ($GetIP) { write-host "Getting IP information from IP commander - this will take around $($Computers.count * 3) seconds" } $DeviceList = @() ForEach ($Computer in $Computers) { #Ignore inactive computers IF ($Computer."status.name" -like "*no longer active*") { continue } #Get DRAC IP IF ($NoDRAC) { $DRAC_IP = $null } Else { IF ($Computer.dracnet_ip.load_value) { $DRAC_IP = Get-CoreIP -ID $($Computer.dracnet_ip.load_value) } else { $DRAC_IP = $null } } #Get IPs from IP commander IF ($GetIP) { $IPs = Get-IPsfromIPCommander -Device $Computer.number } [string]$name = $Computer.name $DevicePSO = [PSCustomObject]@{ Name = $Computer.name; Number = $Computer.number; IP = $Computer.primary_ip; PrivateIP=$Computer.primary_nat_ip; BackupIP=""; OSname=$Computer.os_name; NickName=$Computer.nickname; OStype=$Computer.os_type; PlatName=$Computer.platform_name; PlatType=$Computer.platform_type; Status=$Computer."status.name"; Datacenter=$Computer."datacenter.name"; DatacenterSymbol =$Computer."datacenter.symbol"; Ports=$Computer.ports.display_name; vCenter=$Computer.vcc; Offline=$Computer.offline_date; attached_firewalls = $Computer.attached_firewalls; "Account Name" = $Computer."account.name"; dracnet_ip = $DRAC_IP; Backup_IP = ""; attached_devices = $Computer.attached_devices; Account = $Computer.account.load_value; ServerName = ($name.Split(".")[0]); is_windows = $Computer.is_windows; offline_date = $Computer.offline_date; date_online = $Computer.date_online; dateonline = $Computer.date_online; Domain = $Computer."account_domain_info.domain_name"; IntensiveAddDomain = $Computer."account_domain_info.add_userid_to_domain"; aggexnet_vlans = $Computer.aggexnet_vlans is_cluster = $Computer."is_cluster"; ServiceNetGW = $IPs.ServiceNetGW ServiceNetIP = $IPs.ServiceNetIP ServiceNetNM = $IPs.ServiceNetNM PublicGW = $IPs.PublicGW PublicIP = $IPs.PublicIP PublicNM = $IPs.PublicNM PrivateGW = $IPs.PrivateGW PrivateNM = $IPs.PrivateNM } If ($RackPW) { Add-Member -InputObject $DevicePSO -NotePropertyName RackPass -NotePropertyValue $Computer.rack_password; Add-Member -InputObject $DevicePSO -NotePropertyName AdminPass -NotePropertyValue $Computer.root_password; } $DeviceList += $DevicePSO } Return $DeviceList } function Get-CoreDevicesAccount { Param( [Parameter(mandatory=$true)]$Account, [Parameter()]$limit = 250, [Parameter()][switch]$NoDRAC, [Parameter()][switch]$RackPW, [Parameter()][switch]$GetIP #get ips from IP commander (adds 3 seconds) ) #get our JSON If ($RackPW) { $obj = Get-COREDeviceJSON -Account $Account -RackPW -limit $limit } else { $obj = Get-COREDeviceJSON -Account $Account -limit $limit } $offset = 0 $Computers = @() do { #write to screen what we are doing write-host "Getting devices $offset to $($limit + $offset) from CORE..." #Update our offset in the JSON $obj.load_arg.offset = $offset #Convert it again $JSON = $obj | ConvertTo-Json #Query CORE $QueryResult = "" $QueryResult = (Get-CoreQuery -JSON $JSON).Result #Add result to array $Computers += $QueryResult $oldoffset = $offset $offset = $offset + $limit #debug #write-host "limit $limit" -ForegroundColor Yellow #write-host "QueryResult.created $(($QueryResult.created).count)" -ForegroundColor Yellow } Until (($QueryResult.created).count -lt $limit) $Params = @{ Computers = $Computers; } #Add additional params from the script If ($NoDRAC) { $Params.Add("NoDRAC", $true) } If ($RackPW) { $Params.Add("RackPW", $true) } If ($GetIP) { $Params.Add("GetIP", $true) } $ReturnedComputers = Get-COREDevicePSobject @params Return $ReturnedComputers } Function Get-COREDeviceJSON { Param( [Parameter()]$Device, [Parameter()]$Ticket, [Parameter()]$Account, [Parameter()]$Limit, [Parameter()][switch]$RackPW ) #get our computer attributes If ($RackPW) { $ComputerAttributes = Get-ComputerAttributes -RackPW } else { $ComputerAttributes = Get-ComputerAttributes } If ($Ticket) { #Create JSON object for ticket $obj = @( @{ "load_arg" = $ticket; "class" = "Ticket.Ticket"; "attributes" = @( "id", @{ "id" = "number" "attribute" = "computers" "subattributes" = $ComputerAttributes } ) } ) #Convert it $JSON = $obj | ConvertTo-Json -Depth 10 } If ($Account) { #Create JSON object $json = @( @{ "class" = "Computer.Computer"; "attributes" = $ComputerAttributes "load_arg" = @{ "class" = "Computer.ComputerWhere" "values" = @("account","=","$Account") "offset" = 0 "limit" = $limit } } ) } If ($Device) { #Create JSON object $obj = @( @{ "class" = "Computer.Computer"; "load_arg" = $Device "attributes" = $ComputerAttributes } ) #Convert it $JSON = $obj | ConvertTo-Json -Depth 10 } return $JSON } function Get-CoreDevicesTicket { Param( [Parameter(mandatory=$true)]$Ticket, [Parameter()][switch]$NoDRAC, [Parameter()][switch]$RackPW, [Parameter()][switch]$GetIP #get ips from IP commander (adds 3 seconds) ) #get our JSON If ($RackPW) { $JSON = Get-COREDeviceJSON -Ticket $Ticket -RackPW } else { $JSON = Get-COREDeviceJSON -Ticket $Ticket } #Query CORE $QueryResult = (Get-CoreQuery -JSON $JSON) #As we query subattributes when going via ticket, we need to expand the properties out $Computers = @() $ComputerList = $QueryResult.result.computers.subattributes | gm -MemberType NoteProperty | Select-Object Name ForEach ($Name in $ComputerList) { $Computers += $QueryResult.result.computers.subattributes."$($Name.Name)" } $Params = @{ Computers = $Computers; } #Add additional params from the script If ($NoDRAC) { $Params.Add("NoDRAC", $true) } If ($RackPW) { $Params.Add("RackPW", $true) } If ($GetIP) { $Params.Add("GetIP", $true) } $ReturnedComputers = Get-COREDevicePSobject @params Return $ReturnedComputers } function Get-IPsfromIPCommander { Param( [Parameter (Mandatory=$true)]$Device ) #Skip SSL errors [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} #Create the connection $WebService = New-WebServiceProxy -Uri "https://ipadmin.dcx.rackspace.com/ipadmin/ip_info/wsdl" -UseDefaultCredential #get IPs by device $IPs = $WebService.IpsByDevice("$device") #create psobject from results and return it $Output = New-Object PSObject #filter secondary IPs to get servicenet $servicenet = $IPs.secondary_ips | Where-Object {($_.descriptor -eq "servicesnet") -OR ($_.descriptor -eq "Managed Backup")} #servicenet Add-Member -InputObject $Output -MemberType NoteProperty -Name ServiceNetGW -Value $servicenet.gateway_ip Add-Member -InputObject $Output -MemberType NoteProperty -Name ServiceNetIP -Value $servicenet.ip_address Add-Member -InputObject $Output -MemberType NoteProperty -Name ServiceNetNM -Value $servicenet.netmask #public Add-Member -InputObject $Output -MemberType NoteProperty -Name PublicGW -Value $IPs.primary_ip[0].gateway_ip Add-Member -InputObject $Output -MemberType NoteProperty -Name PublicIP -Value $IPs.primary_ip[0].ip_address Add-Member -InputObject $Output -MemberType NoteProperty -Name PublicNM -Value $IPs.primary_ip[0].netmask #private Add-Member -InputObject $Output -MemberType NoteProperty -Name PrivateGW -Value $IPs.primary_ip[0].inside_local_gateway_ip Add-Member -InputObject $Output -MemberType NoteProperty -Name PrivateIP -Value $IPs.primary_ip[0].inside_local Add-Member -InputObject $Output -MemberType NoteProperty -Name PrivateNM -Value $IPs.primary_ip[0].inside_local_netmask return $output } function Get-CoreDevices{ Param( [Parameter ()][string] $Account, [Parameter ()][switch] $NoOutput, [Parameter ()][string] $Ticket, [Parameter ()][switch] $NoDRAC, [Parameter ()][switch] $RackPW ) IF ($Account) { $Params = @{ Account = $Account } If ($NoDRAC){$Params.Add("NoDRAC", $true)} If ($RackPW){$Params.Add("RackPW", $true)} Get-CoreDevicesAccount @Params } ELSEIF ($Ticket) { $Params = @{ Ticket = $Ticket } If ($NoDRAC){$Params.Add("NoDRAC", $true)} If ($RackPW){$Params.Add("RackPW", $true)} Get-CoreDevicesTicket @Params } ELSE { break } <# .SYNOPSIS RETIRED -> Use Get-CoreDevicesAccount and Get-CoreDevicesTicket .DESCRIPTION RETIRED -> Use Get-CoreDevicesAccount and Get-CoreDevicesTicket .EXAMPLE RETIRED -> Use Get-CoreDevicesAccount and Get-CoreDevicesTicket .EXAMPLE RETIRED -> Use Get-CoreDevicesAccount and Get-CoreDevicesTicket #> } function Get-CoreDevice { Param( [Parameter (Position=1, Mandatory=$true)] [string] $Device, [Parameter()][switch]$NoDRAC, [Parameter()][switch]$RackPW, [Parameter()][switch]$GetIP #get ips from IP commander (adds 3 seconds) ) #get our JSON If ($RackPW) { $JSON = Get-COREDeviceJSON -device $device -RackPW } else { $JSON = Get-COREDeviceJSON -device $device } #Query CORE $Computers = (Get-CoreQuery -JSON $JSON).Result $Params = @{ Computers = $Computers; } #Add additional params from the script If ($NoDRAC) { $Params.Add("NoDRAC", $true) } If ($RackPW) { $Params.Add("RackPW", $true) } If ($GetIP) { $Params.Add("GetIP", $true) } $ReturnedComputers = Get-COREDevicePSobject @params Return $ReturnedComputers <# .SYNOPSIS The Get-CoreDevice cmdlet retrieve details for specified device. The results will be output in format-list. The variable $Device will also be available at cmd line for use in scripts. .DESCRIPTION See synopsis. .EXAMPLE PS C:\Users\Administrator> Get-CoreDevice -Device 24645 This example shows how to retrieve device details #> } Function Get-CoreTicketDevices { Param ( [Parameter(Mandatory=$true)]$ticket = (Read-Host("Enter Ticket Number")) ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreTicketDevices function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---LEGACY FUNCTION IN USE!" -noconsole $DeviceList = Get-CoreDevices -Ticket $ticket return $DeviceList #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreTicketDevices function" -noconsole <# .SYNOPSIS Get-CoreTicketDevices is present to support legacy scripts Please use Get-CoreDevices -Ticket $ticket instead .DESCRIPTION See synopsis. .EXAMPLE Use Get-CoreDevices -Ticket $ticket instead #> } Function Get-CoreTicket { Param ( [Parameter(Mandatory=$true)]$ticket = (Read-Host("Enter Ticket Number")) ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreTicket function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---LEGACY FUNCTION IN USE!" -noconsole $DeviceList = Get-CoreDevices -Ticket $ticket return $DeviceList #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreTicket function" -noconsole <# .SYNOPSIS Get-CoreTicket is present to support legacy scripts Please use Get-CoreDevices -Ticket $ticket instead .DESCRIPTION See synopsis. .EXAMPLE Use Get-CoreDevices -Ticket $ticket instead #> } Function Get-CoreTicketContents { Param ( [Parameter(Mandatory=$true)]$ticket = (Read-Host("Enter Ticket Number")) ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreTicketContents function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ticket = $ticket" -noconsole $obj = @( @{ "class" = "Ticket.Ticket"; "attributes" = @( "id", "account", "subject", "status", "messages", "is_scheduled_service", "assignee", "queue", "difficulty", "created" ) } ) $obj[0]['load_arg'] = $ticket $JSON = $obj | ConvertTo-Json Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON #Expand the assignee ID to the actual name Try{ Add-Member -InputObject $result.result -MemberType NoteProperty -Name Assignee_ID -Value $($result.result.assignee.load_value) $result.result.assignee = (Get-CoreContact -ID $result.result.assignee.load_value).Name } Catch{ #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ERROR TRAP in Get-CoreTicketContents" -noconsole } Return $result.result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreTicketContents function" -noconsole } Function Get-CoreTicketMessage { Param ( [Parameter(Mandatory=$true)]$ID ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreTicketMessage function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ID = $ID" -noconsole $obj = @( @{ "class" = "Ticket.Message"; "attributes" = @( "text", "is_visible", "is_customer", "date", "private", "contact", "source", "id", "contact" ) } ) $obj[0]['load_arg'] = $ID $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreTicketMessage function" -noconsole } Function Get-AccountTeam { Param ( [Parameter(Mandatory=$true)]$Account ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-AccountTeam function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "Account = $Account" -noconsole $obj = @( @{ "class" = "Account.Account"; "attributes" = @( "account_exec", "primary_lead_tech", "business_development", "am_queue" ) } ) $obj[0]['load_arg'] = $Account $JSON = $obj | ConvertTo-Json -Depth 10 $result = "" $result = Get-CoreQuery -JSON $JSON $Contacts = @() Try{ $Contacts += Get-CoreContact -ID $result.result.primary_lead_tech.load_value } Catch { #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "lead tech not found, this is probably intensive managed" -type error $Contacts += $false } $Contacts += Get-CoreContact -ID $result.result.account_exec.load_value $Contacts += Get-CoreContact -ID $result.result.business_development.load_value $Contacts += $result.result.am_queue.id Return $Contacts #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-AccountTeam function" -noconsole } Function Get-CoreContact { Param ( [Parameter(Mandatory=$true)]$ID ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreContact function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ID = $ID" -noconsole $obj = @( @{ "class" = "Contact.Contact"; "attributes" = @( "first_name", "last_name", "name", "primary_email", "employee_userid", "id", "teams", "title", "org", "ldap_groups", "individual", "departments", "imaway" ) } ) $obj[0]['load_arg'] = $ID $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreContact function" -noconsole } Function Get-CoreEmail { Param ( [Parameter(Mandatory=$true)]$ID ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreEmail function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ID = $ID" -noconsole $obj = @( @{ "class" = "Contact.Email"; "attributes" = @( "address" ) } ) $obj[0]['load_arg'] = $ID $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreEmail function" -noconsole } Function Set-CoreTicketAssignee { Param ( [Parameter(Mandatory=$true)]$ID, [Parameter(Mandatory=$true)]$Ticket ) Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/attribute/Ticket/$ticket/assignee" -Method "Post" -Headers @{"X-Auth"=$global:token} -Body "$ID" | Out-Null } Function Set-CoreTicketQueue { Param ( [Parameter(Mandatory=$true)]$Ticket, [Parameter(Mandatory=$true)]$queue ) Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/attribute/Ticket/$ticket/queue" -Method "Post" -Headers @{"X-Auth"=$global:token} -Body "$queue" | Out-Null #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Set-CoreTicketQueue function" -noconsole } Function Get-CoreTicketDetails { Param ( [Parameter(Mandatory=$true)]$Ticket ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreTicketDetails function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "Ticket = $Ticket" -noconsole $obj = @( @{ "class" = "Ticket.Ticket"; "attributes" = @( "account", "subject", "status", "messages", "is_scheduled_service", "superticket" ) } ) $obj[0]['load_arg'] = $Ticket $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreTicketDetails function" -noconsole } Function Get-CoreIP { Param ( [Parameter(Mandatory=$true)]$ID ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Get-CoreIP function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "ID = $ID" -noconsole $obj = @( @{ "class" = "IPSpace.IPAssignment"; "attributes" = @( "ip_address" ) } ) $obj[0]['load_arg'] = $ID $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result.ip_address #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Get-CoreIP function" -noconsole } Function Set-CoreTicketDifficulty { Param ( [Parameter(Mandatory=$true)]$Difficulty, [Parameter(Mandatory=$true)]$Ticket ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Set-CoreTicketDifficulty function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "Difficulty = $Difficulty" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "Ticket = $Ticket" -noconsole Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/attribute/Ticket/$ticket/difficulty" -Method "Post" -Headers @{"X-Auth"=$global:token} -Body "$Difficulty" | Out-Null #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Set-CoreTicketDifficulty function" -noconsole } Function Set-CoreTicketAssigneeByLogin { Param ( [Parameter(Mandatory=$true)]$Ticket ) #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---Start of Set-CoreTicketAssigneeByLogin function" -noconsole #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "Ticket = $Ticket" -noconsole $JSON=@" [ { "class": "Ticket.Ticket", "load_arg": "$Ticket", "set_attribute": { "assignee": { "class": "Contact.Contact", "load_arg": { "class": "Contact.ContactWhere", "values": [ [ "employee_userid", "=", "$([Environment]::UserName)" ] ] } } } } ] "@ Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON #Return $result #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Set-CoreTicketAssigneeByLogin function" -noconsole } Function Add-COREDeviceToTicket { Param( [Parameter(Mandatory=$true)]$Device, [Parameter(Mandatory=$true)]$ticket ) $obj = @( @{ "class" = "Ticket.Ticket"; "method" = "addComputer"; "args" = @( "$Device" ) } ) $obj[0]['load_arg'] = $ticket $JSON = $obj | ConvertTo-Json -Depth 10 $response = Invoke-RestMethod -Uri "https://ws.core.rackspace.com/ctkapi/query" -Method "Post" -Headers @{"X-Auth"=$global:token} -Body $JSON Return $response.Success } Function Update-CoreTicket{ Param( [Parameter(Mandatory=$true)][string]$Ticket, [Parameter(Mandatory=$true)][string]$Message, [Parameter()][Int]$Source=4, [Parameter()][Int]$Private=1, [Parameter()][Int]$source_contact=0, [Parameter()][Int]$send_message_text=0, [Parameter()][Int]$contact=0, [Parameter()][Int]$send_email=0, [Parameter()][Int]$message_time, [Parameter()][Int]$has_bbcode=0 ) <#Source source 1 Customer [Phone Call] source 2 Customer [MyRackspace] source 3 Rackspace Employee source 4 CORE source 5 Customer [Genie] source 6 Customer [Mass Ticket] source 7 Customer [Walk-Up] source 8 Customer [EZCASH] source 9 Customer [Email] source 10 Customer [Other] source 11 Customer [Chat Support] source 12 Customer [RunBook] source 13 Customer [RackerApp] #> Validate-CoreToken $unixEpochStart = new-object DateTime 1970,1,1,0,0,0,([DateTimeKind]::Utc) $message_time = [int]([DateTime]::UtcNow - $unixEpochStart).TotalSeconds #update JSON with variables $JSON = ' [ { "class": "Ticket.Ticket", "load_arg": "'+$Ticket +'", "method": "addMessage", "args": [ "'+$Message+'", '+$Source+', '+$Private+', '+$source_contact+', '+$send_message_text+', '+$contact+', '+$send_email+', '+$message_time+', '+$has_bbcode+' ] } ] ' $result = Get-CoreQuery -JSON $JSON #Check CORE confirms update was a success, or write failure to screen IF($result.Success -ne "True") { Write-host "failed to update ticket" } #Update-Logfile -logfilepath $Global:CTKCoreLogPath -Message "---End of Update-CoreTicket function" -noconsole <# .SYNOPSIS The Update-Ticket cmdlet will update tickets in CORE .DESCRIPTION See synopsis. private: Boolean determining if the Contact cannot see it. source_contact: Who created the message. send_message_text: Boolean determining if text of message should be included in e-mail. has_bbcode: Boolean value informing ticket renderer there is BBCode inside .Parameter Message The ticket update message. Example: Update-Ticket -Ticket "131119-05919" -Message "update test from powershell" .Parameter Source The ticket update source. I wouldn't change this unless you need too. #https://ws.core.rackspace.com/ctkapi/browse/Ticket/Source #Using a customer source forces ticket to be public then marked as private .Parameter Private Private or public update. If you do a public update on a private ticket, CORE will automatically change it Private by default (0) Example: Update-Ticket -Ticket "131119-05919" -Message "Public update test from powershell" -Private 0 .Parameter source_contact Who created the message. Do not change this unless you have a reason too as it defaults to your login name .Parameter send_message_text Boolean determining if text of message should be included in e-mail. Do not change this unless you have a reason too .Parameter contact Do not change this unless you have a reason too .Parameter send_email Do not change this unless you have a reason too .Parameter message_time Do not change this unless you have a reason too .Parameter has_bbcode Enable BBCode in the ticket Example: Update-Ticket -Ticket "131119-05919" -Message "Public update test from powershell" -has_bbcode 1 .EXAMPLE Update-Ticket -Ticket "131119-05919" -Message "update test from powershell" This example shows how to add a private update .EXAMPLE Update-Ticket -Ticket "131119-05919" -Message "Public update test from powershell" -Private 0 This example shows how to add a public update .EXAMPLE Update-Ticket -Ticket "131119-05919" -Message "Public update test from powershell" -Private 0 -has_bbcode 1 This example shows how to add a public update with BBCode .Notes Written by Martin Howlett - martin.howlett@rackspace.co.uk #> } Function Get-CoreTicketSummary { <# .Synopsis Summary of all tickets in a given time frame for an account .Description The Get-CoreTicketSummary cmdlet will pull a list of all tickets for a customer within a given time frame. .Example Get-CoreTicketSummary -Account 24645 -StartDate "2015-01-01- 00:00:00" -EndDate "2015-01-31 23:59:59" This example shows how to retrive a list of tickets for the customer between 1st Jan 2015 00:00:00 and 31st Jan 2015 at 23:59:59 .Example Get-CoreTicketSummary -Account 24645 This example shows how to retrive a list of tickets for the customer between 1st day of the month 00:00:00 to the last day of the month at 23:59:59 for the last month. For example if it was March 18th, this command would pull everything from 1st-28th Feburary. #> Param( [Parameter(Mandatory=$true)][string]$Account, [Parameter()][string]$StartDate, [Parameter()][string]$EndDate, [Parameter()][switch]$UseLastMonth ) If($UseLastMonth){ $date = Get-Date $numMonthsAgo = -1 $startofmonth = Get-Date $date -day 1 -hour 0 -minute 0 -second 0 $endofmonth = (($startofmonth).AddMonths(1).AddSeconds(-1)) $firstDayOfMonth = $startofmonth.AddMonths($numMonthsAgo) $lastDayOfMonth = $endofmonth.AddMonths($numMonthsAgo) } $limit = 50 $offset = 0 $result = @() do { $JSON = @" [ { "class": "Ticket.Ticket", "load_arg": { "class": "Ticket.TicketWhere", "values": [ [ "account", "=", "$Account" ], "&", [ "created", ">", "$($firstDayOfMonth.ToString("yyyy-MM-dd HH:mm:ss"))" ], "&", [ "created", "<", "$($LastDayOfMonth.ToString("yyyy-MM-dd HH:mm:ss"))" ] ], "limit": $limit, "offset": $offset }, "attributes": [ "number", "status.name", "subject", "source", "created", "creator.name", "severity.name", "classification.name", "category.name", "subcategory.name", "last_response_date", "computers", { "attribute": "computers", "subattributes": [ "name" ] } ] } ] "@ Validate-CoreToken $QueryResult = "" $QueryResult = (Get-CoreQuery -JSON $JSON).Result $result += $QueryResult $offset = $offset + $limit }Until (($QueryResult.created).count -lt $limit) $Tickets = @() foreach($Ticket in $result){ [string]$lstComputers = "" $arrComp = @() ForEach ($Comp in $Ticket.Computers.subattributes){ [string]$strComp = $Comp.name $arrComp += $strComp.Split(".")[0] } $lstComputers = $arrComp -join " : " $Tickets += [PSCustomObject]@{ TicketID=$Ticket.number; Status=$Ticket."status.name"; Subject=$Ticket."subject"; Created=$Ticket.created; Creator=$Ticket."creator.name"; Severity=$Ticket."severity.name"; Classification=$Ticket."classification.name"; Category=$Ticket."category.name"; SubCategory=$Ticket."subcategory.name"; Last_Response_Date=$Ticket.last_response_date; Source=$Ticket.source.name; Devices=$lstComputers; } } Return $Tickets } #Use with CTKCoreTestCode.ps1 #Function you can use to test/troubleshoot Json. #Author:Mark Wichall Function Test-CTKJson { Param ( [Parameter()]$JSON ) Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON return $result.result } Function Get-CoreSSLCertificate { Param ( [Parameter()]$ID, [Parameter()]$Ticket ) #$ID = "150117-06312" #$ID = "2105454" IF ($ID) { $loadArg = $ID } ELSE { $loadArg = $Ticket } $obj = @( @{ "class" = "Certificate.Certificate"; "attributes" = @( "account", "active", "cert", "company_name", "csr", "customer_ticket", "domain_name", "end_date", "id", "order_number", "pretty_end_date", "private_key", "start_date", "state", "status", "ticket", "product_type", "computers" ) } ) $obj[0]['load_arg'] = $loadArg $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result <# $JSON=@" [ { "class": "Certificate.Certificate", "load_arg": { "class": "Certificate.CertificateWhere", "values": [ [ "ticket", "=", "140909-04864" ] ], "limit": 200, "offset": 0 }, "attributes": [ "id" ] } ] "@ #> } Function Get-CoreDeviceSKU { Param ( [Parameter(Mandatory=$true)]$Device ) $JSON = @" [ { "class": "Computer.Computer", "load_arg": $Device, "attributes": [ "number", { "attribute": "parts", "subattributes": { "Description": "ctk_product.description", "sku": "sku_number", "label": "display_label", "modified": "modified", "part_attributes": { "attribute": "partributes", "subattributes": [ "value", "sku_attribute.description" ] } } } ] } ] "@ Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON $SKUs = $result.result.parts.subattributes $SKUarr = @() ForEach ($Sku in $SKUs) { $temp = "" $temp = New-Object PSObject -Property @{ SKU = $Sku.Sku Value = $Sku.part_attributes.subattributes.value ValueLabel = $Sku.part_attributes.subattributes."sku_attribute.description" Label = $sku.label Description = $sku.Description Server = $Device } $SKUarr += $temp } Return $SKUarr } Function New-CoreSubTicket{ Param( [Parameter(Mandatory=$true)][string]$MasterTicket, [Parameter(Mandatory=$true)][string]$Subject, [Parameter(Mandatory=$true)][string]$FirstComment, [Parameter()][Int]$Queue=26, [Parameter()][Int]$priority=1, [Parameter()][Int]$severity=1, [Parameter()][array]$computers, [Parameter()][Int]$is_private_message=1, [Parameter()][Int]$is_private_ticket=1 ) $obj = @{ "class"= "Ticket.Ticket"; "load_arg"= "$MasterTicket"; "method"= "addSubTicket"; "args"= @( "$Subject", "$FirstComment", "$Queue", $priority, $severity, $computers, $is_private_message, $is_private_ticket ) } $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON return $result.result.load_value <# .SYNOPSIS .DESCRIPTION See synopsis. .Notes Written by Martin Howlett - martin.howlett@rackspace.co.uk #> } Function Get-ClusterHostfile{ param( [Parameter()]$Devices ) #Create the arrays we will use $Nodes =@() $VirtualComputers =@() $NodesBackup =@() $VirtualComputersBackup =@() $Heartbeats =@() $Blank =@() IF ($HeartbeatIP.Length -lt 1) {$HeartbeatIP = 0} #The domain is often incorrect on virtual servers, so we get the domain for the first node and use that $Node1 = ($devices | Where-Object {$_.is_cluster -ne $True})[0] $Domain = $Node1.Domain ForEach ($Device in $Devices) { #we null values first to stop errors with previous loops $ServiceNetIP = $null $PrivateIP = $null $Account = $null $Number = $null $NoBackup = $null $Account = $Device.Account $Number = $Device.number $Name = $Device.ServerName write-host "Generating hostfile entries for $($Device.ServerName), please wait..." -ForegroundColor Cyan if($Device.Domain -ne $domain){ $DomainError = $true write-host "ERROR! Domain doesn't match for all devices so using domain from first node. Please manually check as CORE could be incorrect" -ForegroundColor Red } #check name and exclude if NT or MSDTC If (($Name -like "*-NT*") -OR ($Name -like "*MSDTC*")){ $NoBackup = $true } $IPs = Get-IPsfromIPCommander -Device $Number $ServiceNetIP = $IPs.ServiceNetIP $PrivateIP = $IPs.PrivateIP #check to make sure its not blank If((-NOT $ServiceNetIP) -AND (-NOT $NoBackup)){ $ServiceNetIP = "BLANK" $Blank += $Number write-host "ERROR! Blank ServiceNet for $name, please manually add" -ForegroundColor Red } #check if its a virtual cluster device IF ($Device.is_cluster){ #build the line for the host file for the nat ip $VirtualComputers += "$PrivateIP $Name $Name.$Domain" IF (-NOT $NoBackup){ #and the line for the backup ip $VirtualComputersBackup += "$ServiceNetIP $Account-$Number" } #if its not a virtual device, it must be a node }ELSE{ #build the line for the host file for the nat ip $Nodes += "$PrivateIP $Name.$Domain" IF (-NOT $NoBackup){ #and the line for the backup ip $NodesBackup += "$ServiceNetIP $Account-$Number" } #increase the heartbeat IP by 1 and build the heartbeat IP $HeartbeatIP ++ $Heartbeats += "10.10.10.$HeartbeatIP heartbeat$HeartbeatIP" } } #Create the temp text file for the hostfile #$Hostfiletemp = "C:\RS-PKGS\hostfile.txt" #New-Item $Hostfiletemp -Type File -Force | Out-Null #Write out to the new lines to an array $newlines = @() If($Blank){$newlines += "WARNING! BLANK SERVICENET DETECTED FOR $($Blank -join ",")!!"} If($DomainError){$newlines += "WARNING! DOMAIN IS NOT THE SAME FOR ALL DEVICES, USING DOMAIN FROM 1ST NODE!!"} $newlines += " " $newlines += " " $newlines += "#Node IPs" $newlines += "$(($Nodes) | Out-String)" $newlines += "#Cluster device IPs" $newlines += "$($VirtualComputers | Out-String)" $newlines += "#Heartbeat IPs" $newlines += "$($HeartBeats | Out-String)" $newlines += "#Node backup IPs" $newlines += "$($NodesBackup | Out-String)" $newlines += "#Cluster device backup IPs" $newlines += "$($VirtualComputersBackup | Out-String)" #Add them to the temp file we created #Add-content $Hostfiletemp -value $newlines | Out-Null #Update-Hostfile -newlines $newlines return $newlines } Function New-CoreTicket{ Param( [Parameter(Mandatory=$true)][Int]$Account, [Parameter(Mandatory=$true)][Int]$Queue=26, #Intensive(All teams) [Parameter()][Int]$subcategory=13376, #Windows - Other [Parameter()][Int]$source=3, #Rackspace Employee [Parameter()][Int]$severity=1, #Standard [Parameter(Mandatory=$true)][String]$subject, [Parameter(Mandatory=$true)][String]$text, [Parameter()]$computer_list=$null, [Parameter()][Int]$is_private_message=1, [Parameter()]$contact_list=$null, [Parameter()]$assignee=$null, [Parameter()]$source_contact=$null, [Parameter()][Int]$is_private_ticket=1, [Parameter()][Int]$send_message_text=0, [Parameter()]$status=$null, [Parameter()]$contact_email_type=$null, [Parameter()][Int]$priority=1, [Parameter()]$product_suite_name=$null, [Parameter()]$product_name=$null, [Parameter()]$action_name=$null, [Parameter()]$classification=$null, [Parameter()]$message_time=$null, [Parameter()]$required_receipients=$null, [Parameter()][Int]$has_bbcode=0 ) $obj = @{ "class"= "Account.Account"; "load_arg"= "$Account"; "method"= "addTicket"; "args"= @( $queue, $subcategory, $source, $severity, $subject, $text, $computer_list, $is_private_message #I cant get core to work with a null contact list so i cant add any more options #$contact_list #$assignee, #$source_contact, #$is_private_ticket, #$send_message_text #$status, #$contact_email_type, #$priority, #$product_suite_name=, #$product_name, #$action_name, #$classification, #$message_time, #$required_receipients, #$has_bbcode ) } $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON return $result.result.load_value <# .SYNOPSIS .DESCRIPTION See synopsis. .Notes Written by Martin Howlett - martin.howlett@rackspace.co.uk #> } #Function to test if number is device and return true/false Function Test-COREWindowsDevice{ Param( [Parameter (Mandatory=$true)]$Device ) $obj = @( @{ "class" = "Computer.Computer"; "attributes" = @( "name", "os_type" ) } ) $obj[0]['load_arg'] = $Device $JSON = $obj | ConvertTo-Json -Depth 10 $result = "" $result = Get-CoreQuery -ErrorAction SilentlyContinue -JSON $JSON if( $result.result.os_type -like "*Windows*"){ return $true }else{ return $false } } Function Test-COREAccount{ Param( [Parameter (Mandatory=$true)]$Account ) $obj = @( @{ "class" = "Account.Account"; "attributes" = @( "number" ) } ) $obj[0]['load_arg'] = $Account $JSON = $obj | ConvertTo-Json -Depth 10 $result = "" $result = Get-CoreQuery -ErrorAction SilentlyContinue -JSON $JSON if( $result.result){ return $true }else{ return $false } } Function Set-COREDeviceStatus{ Param( [Parameter(Mandatory=$true)][Int]$DeviceID, [Parameter(Mandatory=$true)][Int]$StatusID, [Parameter(Mandatory=$true)]$Reason ) <# list of statuses #https://ws.core.rackspace.com/ctkapi/browse/Computer/Status -1 Computer No Longer Active 1 Order Submitted 2 Sent Contract 3 Received Contract 4 In Assembly 5 Ready for QC 6 QC Complete/Ready to Rack 9 Segment Configuration 10 Ready for Account Team 12 Online/Complete #> $obj = @{ "class"= "Computer.Computer"; "load_arg"= "$DeviceID"; "method"= "changeStatus"; "args"= @( "$StatusID" ) "keyword_args" = @{ "reason" = "$Reason" } } $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON return $result.result <# .SYNOPSIS .DESCRIPTION See synopsis. .Notes Written by Martin Howlett - martin.howlett@rackspace.co.uk #> } Function Set-CORETicketStatus{ Param( [Parameter(Mandatory=$true)]$Ticket, [Parameter(Mandatory=$true)]$Status ) <# #CASE SENSITIVE https://ws.core.rackspace.com/ctkapi/browse/Ticket/Status 1 New New 2 Closed Closed 3 Unsolved Unsolved 4 REQUIRE Feedback Require feedback from customer. Ticket will automatically be set to Unsolved after 2 days. 5 Request Feedback Request feedback from customer. Ticket will be automatically closed after one week. 6 Confirm Solved Customer has two days to mark this ticket as Unsolved before it is marked as Closed. 7 New New 8 Closed Closed 9 Unsolved Unsolved 10 Awaiting Response Awaiting Response 11 Request Feedback Request feedback from customer. Ticket will be automatically closed after one week. 12 Confirm Solved Customer has two days to mark this ticket as Unsolved before it is marked as Closed. #> $obj = @{ "class"= "Ticket.Ticket"; "load_arg"= "$Ticket"; "method"= "setStatusByName"; "args"= @( "$Status" ) } $JSON = $obj | ConvertTo-Json -Depth 10 Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON return $result.result <# .SYNOPSIS .DESCRIPTION See synopsis. .Notes Written by Martin Howlett - martin.howlett@rackspace.co.uk #> } Function Get-CoreTicketSearch { Param ( [Parameter(Mandatory=$true)]$DeviceID, [Parameter(Mandatory=$true)]$Subject ) $JSON = @" [ { "class": "Ticket.Ticket", "load_arg": { "class": "Ticket.TicketWhere", "values": [ [ [ "computer", "=", "$DeviceID" ], "&", [ "current_state_date", ">=", "2015-07-01 00:00:00" ], "&", [ "subject", "=", "$subject" ] ] ], "limit": 2000, "offset": 0 }, "attributes": [ "number", "subject", "computers.name", "created" ] } ] "@ Validate-CoreToken $result = "" $result = Get-CoreQuery -JSON $JSON Return $result.result }