diff --git a/MAKE.ps1 b/MAKE.ps1 index 83efac1..7f70d6c 100644 --- a/MAKE.ps1 +++ b/MAKE.ps1 @@ -66,7 +66,7 @@ $PackageFilePatternExclusions = @( $here = Split-Path -Parent $MyInvocation.MyCommand.Path -$Version = "0.1.12" +$Version = "0.1.13" $ModuleName = "PSServiceNow" $PackageName = "$ModuleName-v$($version).zip"; diff --git a/PSServiceNow-Changes.psm1 b/PSServiceNow-Changes.psm1 index 2efe73a..8d129a2 100644 --- a/PSServiceNow-Changes.psm1 +++ b/PSServiceNow-Changes.psm1 @@ -78,3 +78,54 @@ function Get-ServiceNowChangeRequest { return $private:result } + +<# +.EXAMPLE + Update-ServiceNowChangeRequest -Values @{ 'state' = 3 } -SysId +#> +function Update-ServiceNowChangeRequest +{ + Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] + [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] + [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [string]$SysId, + + # Hashtable of values to use as the record's properties + [parameter(mandatory=$true)] + [hashtable]$Values, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + if ($Connection -ne $null) + { + Update-ServiceNowTableEntry -Table 'change_request' -Values $Values -Connection $Connection -SysId $SysId + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + Update-ServiceNowTableEntry -Table 'change_request' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL -SysId $SysId + } + else + { + Update-ServiceNowTableEntry -Table 'change_request' -Values $Values -SysId $SysId + } +} + diff --git a/PSServiceNow-Incidents.psm1 b/PSServiceNow-Incidents.psm1 index 3ac7082..8315202 100644 --- a/PSServiceNow-Incidents.psm1 +++ b/PSServiceNow-Incidents.psm1 @@ -93,7 +93,7 @@ function Get-ServiceNowIncident{ # Set the default property set for the table view $DefaultProperties = @('number', 'short_description', 'opened_at') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$DefaultProperties) + $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers @@ -225,3 +225,53 @@ function New-ServiceNowIncident{ } + +<# +.EXAMPLE + Update-ServiceNowIncident-Values @{ 'short_description' = 'updated description'} -SysId +#> +function Update-ServiceNowIncident +{ + Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] + [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] + [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [string]$SysId, + + # Hashtable of values to use as the record's properties + [parameter(mandatory=$true)] + [hashtable]$Values, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + if ($Connection -ne $null) + { + Update-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection -SysId $SysId + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + Update-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL -SysId $SysId + } + else + { + Update-ServiceNowTableEntry -Table 'incident' -Values $Values -SysId $SysId + } +} diff --git a/PSServiceNow-Tables.psm1 b/PSServiceNow-Tables.psm1 index a5ec8ae..7df4b37 100644 --- a/PSServiceNow-Tables.psm1 +++ b/PSServiceNow-Tables.psm1 @@ -216,4 +216,81 @@ function Remove-ServiceNowTableEntry{ # Fire and return $Uri = $ServiceNowURL + "/table/$Table/$SysID" return (Invoke-RestMethod -Uri $uri -Method Delete -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result +} + + +function Update-ServiceNowTableEntry{ +[CmdletBinding(ConfirmImpact='High')] + Param( + # sys_id of the entry we're deleting + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$SysId, + + # Table containing the entry we're deleting + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Table, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + # The URL for the ServiceNow instance being used + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection, + + # Hashtable of values to use as the record's properties + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$Values + + ) + + #Get credential and ServiceNow REST URL + if ($Connection -ne $null) + { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $ServiceNowCredential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' + + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + } + elseif((Test-ServiceNowAuthIsSet)) + { + $ServiceNowCredential = $Global:ServiceNowCredentials + $ServiceNowURL = $global:ServiceNowRESTURL + } + else + { + throw "Exception: You must do one of the following to authenticate: `n 1. Call the Set-ServiceNowAuth cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + } + + $Body = $Values | ConvertTo-Json; + + #Convert to UTF8 array to support special chars such as the danish "�","�","�" + $utf8Bytes = [System.Text.Encoding]::UTf8.GetBytes($Body) + + # Fire and return + $Uri = $ServiceNowURL + "/table/$Table/$SysID" + return (Invoke-RestMethod -Uri $uri -Method Patch -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json").result } \ No newline at end of file diff --git a/PSServiceNow.Tests.ps1 b/PSServiceNow.Tests.ps1 index be3b6c7..0db3b06 100644 --- a/PSServiceNow.Tests.ps1 +++ b/PSServiceNow.Tests.ps1 @@ -28,7 +28,7 @@ Remove-Module PSServiceNow -ErrorAction SilentlyContinue Import-Module $here\PSServiceNow.psd1 Describe "ServiceNow-Module" { - + It "Set-ServiceNowAuth works" { Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should be $true } @@ -40,7 +40,7 @@ Describe "ServiceNow-Module" { -Comment "Comment" -ConfigurationItem $defaults.TestConfigurationItem ` -Caller $defaults.TestUser ` - $TestTicket.short_description | Should be "Testing with Pester" + $TestTicket.short_description | Should be "Testing with Pester" } It "Get-ServiceNowTable works" { @@ -53,7 +53,29 @@ Describe "ServiceNow-Module" { (Get-ServiceNowIncident).Count -gt 0 | Should Match $true } - It "Get-ServiceNowUserGroup works" { + It "Update-ServiceNowIncident works" { + $TestTicket = New-ServiceNowIncident -ShortDescription "Testing Ticket Update with Pester" ` + -Description "Long description" -AssignmentGroup $defaults.TestUserGroup ` + -Category $defaults.TestCategory -SubCategory $Defaults.TestSubcategory ` + -Comment "Comment" -ConfigurationItem $defaults.TestConfigurationItem ` + -Caller $defaults.TestUser ` + + $TestTicket.short_description | Should be "Testing Ticket Update with Pester" + + $Values = + @{ + 'short_description' = 'Ticket Updated with Pester' + 'description' = 'Even Longer Description' + } + + Update-ServiceNowIncident -SysId $TestTicket.sys_id -Values $Values + + $TestTicket = Get-ServiceNowIncident -MatchExact @{sys_id=$TestTicket.sys_id} + $TestTicket.short_description | Should be "Ticket Updated with Pester" + $TestTicket.description | Should be "Even Longer Description" + } + + It "Get-ServiceNowUserGroup works" { # There should be one or more user groups returned (Get-ServiceNowUserGroup).Count -gt 0 | Should Match $true } @@ -68,7 +90,7 @@ Describe "ServiceNow-Module" { (Get-ServiceNowConfigurationItem).Count -gt 0 | Should Match $true } - It "Get-ServiceNowChangeRequest works" { + It "Get-ServiceNowChangeRequest works" { (Get-ServiceNowChangeRequest).Count -gt 0 | Should Match $true } } \ No newline at end of file diff --git a/PSServiceNow.psd1 b/PSServiceNow.psd1 index f8c79b5..22e0fe4 100644 --- a/PSServiceNow.psd1 +++ b/PSServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'PSServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.12' +ModuleVersion = '0.1.13' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -80,8 +80,23 @@ FunctionsToExport = '*' # List of all files packaged with this module # FileList = @() -# Private data to pass to the module specified in RootModule/ModuleToProcess -# PrivateData = '' +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @('Azure','Automation','ServiceNow') + + # A URL to the license for this module. + LicenseUri = 'https://github.com/Sam-Martin/servicenow-powershell/blob/master/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/Sam-Martin/servicenow-powershell' + + } # End of PSData hashtable + +} # End of PrivateData hashtable # HelpInfo URI of this module # HelpInfoURI = 'https://github.com/Sam-Martin/servicenow-powershell' diff --git a/Readme.md b/Readme.md index 4aacfc7..8ae7a55 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ # PSServiceNow -[![GitHub release](https://img.shields.io/github/release/Sam-Martin/servicenow-powershell.svg)](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Sam-Martin/servicenow-powershell.svg)](LICENSE) ![Test Coverage](https://img.shields.io/badge/coverage-70%25-yellowgreen.svg) +[![GitHub release](https://img.shields.io/github/release/Sam-Martin/servicenow-powershell.svg)](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Sam-Martin/servicenow-powershell.svg)](LICENSE) ![Test Coverage](https://img.shields.io/badge/coverage-68%25-yellowgreen.svg) This PowerShell module provides a series of cmdlets for interacting with the [ServiceNow REST API](http://wiki.servicenow.com/index.php?title=REST_API), performed by wrapping `Invoke-RestMethod` for the API calls. -**IMPORTANT:** Neither this module, nor its creator are in any way affiliated with ServiceNow. +**IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow. ## Requirements Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introduced. @@ -24,6 +24,12 @@ Import-Module PSServiceNow Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL ``` +### Example - Update a Ticket +``` +$Incident = Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description='PowerShell'} +Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated via PowerShell'} +``` + ### Azure Connection Object (Automation Integration Module Support) The module can use the `Connection` parameter in conjunction with the included `PSServiceNow-Automation.json` file for use as an Azure automation integration module. Details of the process is available at [Authoring Integration Modules for Azure Automation](https://azure.microsoft.com/en-us/blog/authoring-integration-modules-for-azure-automation). @@ -43,6 +49,9 @@ The `Connection` parameter accepts a hashtable object that requires a username, * Remove-ServiceNowTableEntry * Set-ServiceNowAuth * Test-ServiceNowAuthIsSet +* Update-ServiceNowChangeRequest +* Update-ServiceNowIncident +* Update-ServiceNowTableEntry ## Tests This module comes with [Pester](https://github.com/pester/Pester/) tests for unit testing.